# How do I prevent poor formatting when using ltablex package and nesting tabularx environments?

I'm preparing a long table (> 1 page, so I'm using the longtable package) that is set to take up the full \textwidth of a page. I aim to produce both letter- and A4-sized versions of the document, but as these standards have different sizes, the table with have different widths in each of the documents.

I expect to expand the table some in the future, and I'd like to avoid manually adjusting the relevant length parameters whenever I switch back and forth between the letter and A4 formats. Thus, I am using the tabularx package and (for the rightmost column) the X column type it furnishes that expands so that the table has the designated width. In order to use simultaneously the features of longtable and tabularx I am using the ltablex package, which is designed for this purpose.

On top of this, the rightmost cell of each row of the tabular environment contains another table. This inner table again has one column of type X. The ltablex package redefines the tabularx environment, a consequence of which is that attempting to nest one tabularx environment in another produces an error:

! Extra alignment tab has been changed to \cr. <template> \endtemplate

In an answer to a related question David Carlisle gave a workaround for this issue, defining a command restoretx that restores the ability to nest tabularx environments.

This allows, for example, one to create nested tables, so that, e.g., this m.w.e. compiles and produces the expected results:

\documentclass{article}
\usepackage{blindtext}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{tabularx}

%This block is from David Carlisle's code in the linked question
\makeatletter
\let\tx@\TX@endtabularx
\def\restoretx{\let\TX@endtabularx\tx@}
\makeatother

\usepackage{ltablex}

\newcommand{\innerTable}[2]{
{
\restoretx
\begin{tabularx}{\linewidth}{cX}
#1 & #2 \\
\end{tabularx}
}
}

\setlength{\parindent}{0cm}

\begin{document}
\begin{tabularx}{\linewidth}{cX}
test & \innerTable{test2}{\blindtext[1]} \\
test & \innerTable{test2}{\blindtext[1]} \\
[...about 40 copies of this row in total...]
test & \innerTable{test2}{\blindtext[1]} \\
test & \innerTable{test2}{\blindtext[1]} \\
\end{tabularx}
\end{document}


A typical page:

The number of rows in the above example is not accidental: If we add a small number of additional copies of the row test & \innerTable{test2}{\blindtext[1]} \\ then the file will still compile, but the formatting breaks badly. In this case a typical page now looks like Worse, this behavior is inconsistent across runs: Sometimes a file with 40 copies of the line will compile correctly, other times not.

Consulting the logfile shows the following warning:

Package tabularx Warning: X Columns too narrow (table too wide) (tabularx) on input line 79.

I know that the tabularx package (and so probably the ltablex package) tries to compute for each column of type X an appropriate width by some iterative process, so I suppose this warning means that the package gave up on trying to find a good width.

Is there a way to compel ltablex to try harder to find a good width for an X column, albeit at the cost of time/memory? (The table I'm actually working with is much longer than the one above, ~170 rows.) Or is there another workaround that still uses nested xtabular environments with X columns? If this is hopeless (or even if it's not), what other methods can be used to achieve the same end?

Some possible solutions---and the reasons I initially rejected them---which I might have might have to settle for:

• Another package, ltxtable, also marries longtable and tabularx, and its behavior is somewhat different from ltablex. But (both the installation and use of) this package seems idiosyncratic, including that by default the table code is required to be in a separate file, which I'd like to avoid it possible. (I'd expect this particular limitation can be circumvented by using yet another package.) Edit I attempted this, and the compilation fails altogether, reporting a memory issue: ! TeX capacity exceeded, sorry [text input levels=15].

• Probably I could just measure and hardcode the relevant lengths for both of the two page sizes and write a switch that checks the page size to determine which sizes to use---but this is kludgy and would require actually measuring column sizes (this is feasible, though).

This question is similar, by the way, but the OP's aim there is evidently somewhat different from mine, since the accepted answer thereto (also by David Carlisle, incidentally) uses columns of manually defined widths, which is exactly what I aim to avoid.

Edit A posted answer suggests using the xltabular package instead of the ltablex package. This package has the apparent advantage that one doesn't need to define a command like \restoretx in the m.w.e. above, but using the package it does not resolve the issue in the question. In fact, it produces output whose formatting is broken in essentially the same way:

Edit. The tabularx package is not suited for use as nested tables in some other table. FAs some test show, it can be nested up to 45 time, than the calculation of X column width (in each nested tabularx doesn't work any more.

If this can be resolved is question for package authors.

Meanwhile this limitation can be avoided on two ways:

• main table limit to 45 nested tabularx tables and than repeat main table (what seems to not be an option for OP)
• instead tabularx use tabular* and manually in advance defined width of each columns in nested tables (which can require redefine of ratio between column width after inspection of result of the first compilation)

In both cases I would instead ltablex (which redefines abularx in lots of ways one is that, by default it turns X columns into l columns for small tables) rather use xltabular. For the second case, the solution can be:

\documentclass{article}
\usepackage{lipsum}
\usepackage{booktabs, xltabular}

\newcommand{\innerTable}[2]%
{
\begin{tabular*}{\linewidth}{@{} >{\centering}p{\dimexpr0.12\linewidth-\tabcolsep}
p{\dimexpr0.88\linewidth-\tabcolsep} @{}}
#1 & #2
\end{tabular*}}

\setlength{\parindent}{0cm}
%---------------- show page layout. don't use in a real document!
\usepackage{showframe}
\renewcommand\ShowFrameLinethickness{0.15pt}
\renewcommand*\ShowFrameColor{\color{red}}
%---------------------------------------------------------------%

\begin{document}
\setlength\tabcolsep{4pt}
\begin{xltabular}{\linewidth}{@{} cX @{}}
test & \innerTable{test 1}{\lipsum*[1]}  \\  \addlinespace
test & \innerTable{test 2}{\lipsum*[2]}  \\  \addlinespace
test & \innerTable{test 3}{\lipsum*[3]}  \\  \addlinespace
test & \innerTable{test 4}{\lipsum*[4]}  \\  \addlinespace
test & \innerTable{test 5}{\lipsum*[5]}  \\  \addlinespace

test & \innerTable{test 6}{\lipsum*[6]}  \\  \addlinespace
test & \innerTable{test 7}{\lipsum*[7]}  \\  \addlinespace
test & \innerTable{test 8}{\lipsum*[8]}  \\  \addlinespace
test & \innerTable{test 9}{\lipsum*[9]}  \\  \addlinespace
test & \innerTable{test 10}{\lipsum*[10]} \\  \addlinespace

test & \innerTable{test 11}{\lipsum*[11]} \\  \addlinespace
test & \innerTable{test 12}{\lipsum*[12]} \\  \addlinespace
test & \innerTable{test 13}{\lipsum*[13]} \\  \addlinespace
test & \innerTable{test 14}{\lipsum*[14]} \\  \addlinespace
test & \innerTable{test 15}{\lipsum*[15]} \\  \addlinespace

test & \innerTable{test 16}{\lipsum*[16]} \\  \addlinespace
test & \innerTable{test 17}{\lipsum*[17]} \\  \addlinespace
test & \innerTable{test 18}{\lipsum*[18]} \\  \addlinespace
test & \innerTable{test 19}{\lipsum*[19]} \\  \addlinespace
test & \innerTable{test 20}{\lipsum*[20]} \\  \addlinespace

test & \innerTable{test 21}{\lipsum*[21]} \\  \addlinespace
test & \innerTable{test 22}{\lipsum*[22]} \\  \addlinespace
test & \innerTable{test 23}{\lipsum*[23]} \\  \addlinespace
test & \innerTable{test 24}{\lipsum*[24]} \\  \addlinespace
test & \innerTable{test 25}{\lipsum*[25]} \\  \addlinespace

test & \innerTable{test 26}{\lipsum*[26]} \\  \addlinespace
test & \innerTable{test 27}{\lipsum*[27]} \\  \addlinespace
test & \innerTable{test 28}{\lipsum*[28]} \\  \addlinespace
test & \innerTable{test 29}{\lipsum*[29]} \\  \addlinespace
test & \innerTable{test 30}{\lipsum*[30]} \\  \addlinespace

test & \innerTable{test 31}{\lipsum*[31]} \\  \addlinespace
test & \innerTable{test 32}{\lipsum*[32]}  \\  \addlinespace
test & \innerTable{test 33}{\lipsum*[33]}  \\  \addlinespace
test & \innerTable{test 34}{\lipsum*[34]}  \\  \addlinespace
test & \innerTable{test 35}{\lipsum*[35]}  \\  \addlinespace

test & \innerTable{test 36}{\lipsum*[36]}  \\  \addlinespace
test & \innerTable{test 37}{\lipsum*[37]}  \\  \addlinespace
test & \innerTable{test 38}{\lipsum*[38]}  \\  \addlinespace
test & \innerTable{test 39}{\lipsum*[39]}  \\  \addlinespace
test & \innerTable{test 40}{\lipsum*[40]}  \\  \addlinespace

test & \innerTable{test 41}{\lipsum*[41]}  \\  \addlinespace
test & \innerTable{test 42}{\lipsum*[42]}  \\  \addlinespace
test & \innerTable{test 43}{\lipsum*[43]}  \\  \addlinespace
test & \innerTable{test 44}{\lipsum*[44]}  \\  \addlinespace
test & \innerTable{test 45}{\lipsum*[45]}  \\  \addlinespace

test & \innerTable{test 46}{\lipsum*[46]}  \\  \addlinespace
test & \innerTable{test 47}{\lipsum*[47]}  \\  \addlinespace
test & \innerTable{test 48}{\lipsum*[48]}  \\  \addlinespace
test & \innerTable{test 49}{\lipsum*[49]}  \\  \addlinespace
test & \innerTable{test 50}{\lipsum*[50]}  \\  \addlinespace

test & \innerTable{test 51}{\lipsum*[51]}  \\  \addlinespace
test & \innerTable{test 52}{\lipsum*[52]}  \\  \addlinespace
test & \innerTable{test 53}{\lipsum*[53]}  \\  \addlinespace
test & \innerTable{test 54}{\lipsum*[54]}  \\  \addlinespace
test & \innerTable{test 55}{\lipsum*[55]}  \\  \addlinespace

test & \innerTable{test 56}{\lipsum*[56]}  \\  \addlinespace
test & \innerTable{test 57}{\lipsum*[57]}  \\  \addlinespace
test & \innerTable{test 58}{\lipsum*[58]}  \\  \addlinespace
test & \innerTable{test 59}{\lipsum*[59]}  \\  \addlinespace
test & \innerTable{test 60}{\lipsum*[60]}  \\  \addlinespace

test & \innerTable{test 61}{\lipsum*[61]}  \\  \addlinespace
test & \innerTable{test 62}{\lipsum*[62]}  \\  \addlinespace
test & \innerTable{test 63}{\lipsum*[63]}  \\  \addlinespace
test & \innerTable{test 64}{\lipsum*[64]}  \\  \addlinespace
test & \innerTable{test 65}{\lipsum*[65]}  \\  \addlinespace

test & \innerTable{test 66}{\lipsum*[66]}  \\  \addlinespace
test & \innerTable{test 67}{\lipsum*[67]}  \\  \addlinespace
test & \innerTable{test 68}{\lipsum*[68]}  \\  \addlinespace
test & \innerTable{test 69}{\lipsum*[69]}  \\  \addlinespace
test & \innerTable{test 70}{\lipsum*[70]}  \\  \addlinespace

test & \innerTable{test 71}{\lipsum*[71]}  \\  \addlinespace
test & \innerTable{test 72}{\lipsum*[72]}  \\  \addlinespace
test & \innerTable{test 73}{\lipsum*[73]}  \\  \addlinespace
test & \innerTable{test 74}{\lipsum*[74]}  \\  \addlinespace
test & \innerTable{test 75}{\lipsum*[75]}  \\  \addlinespace

test & \innerTable{test 76}{\lipsum*[76]}  \\  \addlinespace
test & \innerTable{test 77}{\lipsum*[77]}  \\  \addlinespace
test & \innerTable{test 78}{\lipsum*[78]}  \\  \addlinespace
test & \innerTable{test 79}{\lipsum*[79]}  \\  \addlinespace
test & \innerTable{test 80}{\lipsum*[80]}  \\  \addlinespace

test & \innerTable{test 81}{\lipsum*[81]}  \\  \addlinespace
test & \innerTable{test 82}{\lipsum*[82]}  \\  \addlinespace
test & \innerTable{test 83}{\lipsum*[83]}  \\  \addlinespace
test & \innerTable{test 84}{\lipsum*[84]}  \\  \addlinespace
test & \innerTable{test 85}{\lipsum*[85]}  \\  \addlinespace

test & \innerTable{test 86}{\lipsum*[86]}  \\  \addlinespace
test & \innerTable{test 87}{\lipsum*[87]}  \\  \addlinespace
test & \innerTable{test 88}{\lipsum*[88]}  \\  \addlinespace
test & \innerTable{test 89}{\lipsum*[89]}  \\  \addlinespace
test & \innerTable{test 80}{\lipsum*[90]}  \\  \addlinespace

test & \innerTable{test 91}{\lipsum*[1]}  \\  \addlinespace
test & \innerTable{test 92}{\lipsum*[1]}  \\  \addlinespace
test & \innerTable{test 93}{\lipsum*[1]}  \\  \addlinespace
test & \innerTable{test 94}{\lipsum*[1]}  \\  \addlinespace
test & \innerTable{test 95}{\lipsum*[1]}  \\  \addlinespace

test & \innerTable{test 96}{\lipsum*[96]}  \\  \addlinespace
test & \innerTable{test 97}{\lipsum*[97]}  \\  \addlinespace
test & \innerTable{test 98}{\lipsum*[98]}  \\  \addlinespace
test & \innerTable{test 99}{\lipsum*[99]}  \\  \addlinespace
test & \innerTable{test 100}{\lipsum*[100]}%\\  \addlinespace

test & \innerTable{test 101}{\lipsum*[101]}  \\  \addlinespace
test & \innerTable{test 102}{\lipsum*[102]}  \\  \addlinespace
test & \innerTable{test 103}{\lipsum*[103]}  \\  \addlinespace
test & \innerTable{test 104}{\lipsum*[104]}  \\  \addlinespace
test & \innerTable{test 105}{\lipsum*[105]}
\end{xltabular}
\end{document}


(red lines indicates page layout)

Addendum: You can elegantly avoid all problems by aligning of the cells' contents to their top. In this case, table nesting is no longer required, and the table record is shorter:

\documentclass{article}
\usepackage{lipsum}
\usepackage{booktabs, xltabular}

\setlength{\parindent}{0cm}
%---------------- show page layout. don't use in a real document!
\usepackage{showframe}
\renewcommand\ShowFrameLinethickness{0.15pt}
\renewcommand*\ShowFrameColor{\color{red}}
%---------------------------------------------------------------%

\begin{document}
\setlength\tabcolsep{4pt}
\begin{xltabular}{\linewidth}{@{} cc X @{}}
test & test 1 & \lipsum*[1]     \\  \addlinespace
test & test 2 & \lipsum*[2]     \\  \addlinespace
test & test 3 & \lipsum*[3]     \\  \addlinespace
test & test 4 & \lipsum*[4]     \\  \addlinespace
test & test 5 & \lipsum*[5]     \\  \addlinespace
% etc

test & test 101 & \lipsum*[101] \\  \addlinespace
test & test 102 & \lipsum*[102] \\  \addlinespace
test & test 103 & \lipsum*[103] \\  \addlinespace
test & test 104 & \lipsum*[104] \\  \addlinespace
test & test 105 & \lipsum*[105] \\  \addlinespace
\end{xltabular}
\end{document}


which gives (to my opinion, of course) nicer, more professional looking result:

• If the text inside the tables shall line up with text before and after the tables, left and right side bearings of the main table, and the right one on the inner tables, have to be removed. – Sveinung Sep 15 at 11:12
• @Sveinung, apparently I didn't read question enough carefully. Now corrected (by removing tabcolsep from left and right side of tables). – Zarko Sep 15 at 11:41
• Hey Zarko, thanks for the reply---I appreciate the help. This answer does not, however, seem to address the issue. The problem is not that the formatting breaks once the table extends onto a second page: In my post I mentioned that even with 40 rows (sometimes) the entire document renders correctly (and you can see from the screencap shows there only three rows are rendered per page). – Travis Sep 15 at 19:16
• The problem is that the formatting breaks once the table has larger row counts. If I modify your code (only) by changing the number of instances of test & \innerTable{test2}{\lipsum*[1]} \\  from 6 to 50 and compile, the formatting breaks in apparently the same way it does with the ltablex package: i.imgur.com/vHg1XQk.png . (I'll update my question to reflect this additional information.) If you have any more insight/suggestions, I'd be grateful to receive them. Thanks again! – Travis Sep 15 at 19:22
• Hi Zarko, thanks for spending time on this! Since the same number of repetitions sometimes works and sometimes does not, the outcome depends not only on the code but also the system state, which suggests a memory issue. Also, if you try my original code using the landscape option when loading the geometry package you'll find that the threshold beyond which the formatting issue occurs is closer to 20 rows, so the success of the code depends also in a substantial way on page geometry. – Travis Sep 15 at 20:04