[Bug report] Table splits fail due to postponed-content height constraint

Yoshua Wakeham via reportlab-users <[email protected]> Thu, 13 Nov 2025 16:44:52 -0500
Newsgroups gmane.comp.python.reportlab.user
Message-ID <CAPt=5qSZSsoF_0ux8N1JjG_e9oS6aUxN1v6vgo3D529HZ=wf5w@mail.gmail.com>
--000000000000267298064380cbe1
Content-Type: multipart/alternative; boundary="000000000000267297064380cbdf"

--000000000000267297064380cbdf
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi there,

I'd like to draw attention to a bug in within-row table splits.

Note: this one was first reported in 2024 by Christian Zwicknagl in the
Google mirror of this mailing list (link
<https://groups.google.com/g/reportlab-users/c/NhklESoh3mg/m/pO8Ve7VlCgAJ>)=
.
It seems that the report didn't get noticed, because it was only ever
posted to the mirror. I have adapted his test code and patch, but I don't
have his contact details so I haven't been able to communicate with him to
see if he would still be interested in a fix. (Christian, if you're out
there, thank you for reporting this in 2024!)

At present, table row splits will fail if the height of the "postponed"
content exceeds the height of the original row, minus the space available
for the "non-postponed" content. The problem is that this constraint seems
to cause perfectly-valid splits to fail =E2=80=93 and doesn't (as far as I =
can see)
prevent any specific *invalid* split case.

While at first blush it might seem that the sum of the parts of a split row
should always equal the height of the original row, in fact splitting cells
usually introduces some amount of additional padding/space which "inflates"
the height of the row. As Christian reported, it seems that
cells containing many flowables can trigger this split failure fairly
easily.

I've attached a very small example that demonstrates the problem, by
splitting a cell containing just 38 small paragraphs. When run against
reportlab v4.4.4, it fails with a layout error:

reportlab.platypus.doctemplate.LayoutError: Flowable <Table@0x1067B9450 1
rows x 1 cols(tallest row 702)> with cell(0,0) containing
'<Paragraph at 0x1067bebd0>'(200 x 702), tallest cell 702.0 points,  too
large on page 2 in frame 'normal'(439.27559055118115 x 685.8897637795277*)
of template 'Later'


I've attached a patch, adapted from Christian's similar patch, that removes
the height constraint on postponed content =E2=80=93 rather, if we attempt =
to split
a flowable in the cell, then provided that *some* flowable fits in the
first half of the split, we simply postpone everything else.

I've confirmed that with this patch, the example code succeeds. I've also
confirmed that all existing tests pass with this change applied.

Best regards,
Yosh

--=20

*Yoshua Wakeham*
Senior Software Developer
[email protected]

--000000000000267297064380cbdf
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Hi there,</div><div><br></div><div>I&#39;d like to dr=
aw attention to a bug in within-row table splits.</div><div><br></div><div>=
Note: this one was first reported in 2024 by=C2=A0Christian Zwicknagl in th=
e Google mirror of this mailing=C2=A0list (<a href=3D"https://groups.google=
.com/g/reportlab-users/c/NhklESoh3mg/m/pO8Ve7VlCgAJ">link</a>). It seems th=
at the report didn&#39;t=C2=A0get noticed, because it was only ever posted =
to the mirror. I have adapted his test code and patch, but I don&#39;t have=
 his contact details so I haven&#39;t been able to communicate=C2=A0with hi=
m to see if he would still be interested in a fix. (Christian, if you&#39;r=
e out there, thank you for reporting this in 2024!)</div><div><br></div><di=
v>At present, table row splits will fail if the height of the &quot;postpon=
ed&quot; content exceeds the height of the original row, minus the space av=
ailable for the &quot;non-postponed&quot; content. The problem is that this=
 constraint seems to cause perfectly-valid splits to fail =E2=80=93 and doe=
sn&#39;t (as far as I can see) prevent any specific <i>invalid</i>=C2=A0spl=
it case.</div><div><br></div><div>While at first blush it might seem that t=
he sum of the parts of a split row should always equal the height of the or=
iginal row, in fact splitting cells usually introduces some amount of addit=
ional padding/space which &quot;inflates&quot; the height of the row. As Ch=
ristian reported, it=C2=A0seems that cells=C2=A0containing=C2=A0many flowab=
les can=C2=A0trigger=C2=A0this split failure fairly easily.</div><div><br><=
/div><div>I&#39;ve attached a very small example that demonstrates the prob=
lem,=C2=A0by splitting a cell containing just 38 small paragraphs. When run=
 against reportlab v4.4.4, it fails with a layout error:</div><div><br></di=
v><blockquote style=3D"margin:0 0 0 40px;border:none;padding:0px"><div>repo=
rtlab.platypus.doctemplate.LayoutError: Flowable &lt;Table@0x1067B9450 1 ro=
ws x 1 cols(tallest row 702)&gt; with cell(0,0) containing</div><div>&#39;&=
lt;Paragraph at 0x1067bebd0&gt;&#39;(200 x 702), tallest cell 702.0 points,=
 =C2=A0too large on page 2 in frame &#39;normal&#39;(439.27559055118115 x 6=
85.8897637795277*) of template &#39;Later&#39;</div></blockquote><div><br><=
/div>I&#39;ve attached a patch, adapted from Christian&#39;s similar patch,=
 that removes the height constraint on postponed content =E2=80=93 rather, =
if we attempt to split a flowable in the cell, then provided that <i>some</=
i> flowable fits in the first half of the split, we simply postpone everyth=
ing else.<div><br></div><div>I&#39;ve confirmed that with this patch, the e=
xample code succeeds. I&#39;ve also confirmed that all existing tests pass =
with this change applied.</div><div><br></div><div>Best regards,</div><div>=
Yosh</div><div><div><br></div><span class=3D"gmail_signature_prefix">-- </s=
pan><br><div dir=3D"ltr" class=3D"gmail_signature" data-smartmail=3D"gmail_=
signature"><div dir=3D"ltr"><b style=3D"color:rgb(34,34,34)">Yoshua Wakeham=
<br></b><br style=3D"color:rgb(34,34,34)"><span style=3D"color:rgb(34,34,34=
)">Senior Software Developer</span><br style=3D"color:rgb(34,34,34)"><span =
style=3D"color:rgb(34,34,34)">[email protected]</span><br></div></div></div=
></div>

--000000000000267297064380cbdf--

--000000000000267298064380cbe1
Content-Type: text/x-python-script; charset="US-ASCII"; 
	name="repro_split_postponed_content_height_bug.py"
Content-Disposition: attachment; 
	filename="repro_split_postponed_content_height_bug.py"
Content-Transfer-Encoding: base64
Content-ID: <f_mhxyctym0>
X-Attachment-Id: f_mhxyctym0

ZnJvbSByZXBvcnRsYWIucGxhdHlwdXMgaW1wb3J0ICgKICAgIFBhcmFncmFwaCwKICAgIFRhYmxl
LAopCmZyb20gcmVwb3J0bGFiLnBsYXR5cHVzLmRvY3RlbXBsYXRlIGltcG9ydCBTaW1wbGVEb2NU
ZW1wbGF0ZQoKZGF0YSA9IFsoW1BhcmFncmFwaChmIih7eH0pIiArICIgVGhpcyBpcyBhIHNtYWxs
IHBhcmFwcmFwaC4iICogNCkgZm9yIHggaW4gcmFuZ2UoMzgpXSwpXQpjb2xXaWR0aHMgPSAyMDAK
CnQgPSBUYWJsZSgKICAgIGRhdGEsCiAgICBjb2xXaWR0aHM9Y29sV2lkdGhzLAogICAgc3BsaXRJ
blJvdz0xLAopCgpTaW1wbGVEb2NUZW1wbGF0ZSgib3V0cHV0LnBkZiIsIHNob3dCb3VuZGFyeT0x
KS5idWlsZChbdF0pCg==
--000000000000267298064380cbe1
Content-Type: application/octet-stream; 
	name="0001-remove-height-constraint-on-postponed-content.patch"
Content-Disposition: attachment; 
	filename="0001-remove-height-constraint-on-postponed-content.patch"
Content-Transfer-Encoding: base64
Content-ID: <f_mhxyd1et1>
X-Attachment-Id: f_mhxyd1et1

RnJvbSA4Yjk1NmE2NDc3NmVmZTFmZGM0NmRkMDg5MjVjZDM5MjliNTkxMTA5IE1vbiBTZXAgMTcg
MDA6MDA6MDAgMjAwMQpGcm9tOiBZb3NodWEgV2FrZWhhbSA8eW9zaEBhdHRpY3VzLnRlY2g+CkRh
dGU6IFRodSwgMTMgTm92IDIwMjUgMTY6Mzc6MDggLTA1MDAKU3ViamVjdDogW1BBVENIXSByZW1v
dmUgaGVpZ2h0IGNvbnN0cmFpbnQgb24gcG9zdHBvbmVkIGNvbnRlbnQKCi0tLQogc3JjL3JlcG9y
dGxhYi9wbGF0eXB1cy90YWJsZXMucHkgfCAzOCArKysrKysrKysrKystLS0tLS0tLS0tLS0tLS0t
LS0tLQogMSBmaWxlIGNoYW5nZWQsIDE0IGluc2VydGlvbnMoKyksIDI0IGRlbGV0aW9ucygtKQoK
ZGlmZiAtLWdpdCBhL3NyYy9yZXBvcnRsYWIvcGxhdHlwdXMvdGFibGVzLnB5IGIvc3JjL3JlcG9y
dGxhYi9wbGF0eXB1cy90YWJsZXMucHkKaW5kZXggMWJjNTA5MGYuLjQ3ZTQyMWUzIDEwMDc1NQot
LS0gYS9zcmMvcmVwb3J0bGFiL3BsYXR5cHVzL3RhYmxlcy5weQorKysgYi9zcmMvcmVwb3J0bGFi
L3BsYXR5cHVzL3RhYmxlcy5weQpAQCAtMTQ2MCw3ICsxNDYwLDcgQEAgb25seSByb3dzIG1heSBi
ZSBzdHJpbmdzIHdpdGggdmFsdWVzIGluIHtfU1BFQ0lBTFJPV1Mhcn0nJycpCiAgICAgICAgIGlm
IGlzaW5zdGFuY2UodmFsdWUsICh0dXBsZSwgbGlzdCkpOgogICAgICAgICAgICAgbmV3Q2VsbENv
bnRlbnQgPSBbXQogICAgICAgICAgICAgcG9zdHBvbmVkQ29udGVudCA9IFtdCi0gICAgICAgICAg
ICBzcGxpdCA9IEZhbHNlCisgICAgICAgICAgICBmbG93YWJsZV9zcGxpdF9hdHRlbXB0ZWQgPSBG
YWxzZQogICAgICAgICAgICAgRkggPSBbXQogICAgICAgICAgICAgY2VsbEhlaWdodCA9IHNlbGYu
X2xpc3RDZWxsR2VvbSh2YWx1ZSwgd2lkdGgsIHN0eWxlLEg9RkgpWzFdCiAKQEAgLTE0NzEsMjAg
KzE0NzEsMTcgQEAgb25seSByb3dzIG1heSBiZSBzdHJpbmdzIHdpdGggdmFsdWVzIGluIHtfU1BF
Q0lBTFJPV1Mhcn0nJycpCiAKICAgICAgICAgICAgIGZvciBmbG93YWJsZSxfZmggaW4gemlwKHZh
bHVlLEZIKToKICAgICAgICAgICAgICAgICBmbG93YWJsZV9oZWlnaHQgPSBnZXRhdHRyKGZsb3dh
YmxlLCdoZWlnaHQnLF9maCkKLSAgICAgICAgICAgICAgICBpZiBzcGxpdDoKLSAgICAgICAgICAg
ICAgICAgICAgaWYgZmxvd2FibGVfaGVpZ2h0IDw9IGhlaWdodDE6Ci0gICAgICAgICAgICAgICAg
ICAgICAgICBwb3N0cG9uZWRDb250ZW50LmFwcGVuZChmbG93YWJsZSkKLSAgICAgICAgICAgICAg
ICAgICAgICAgICMgU2hyaW5rIHRoZSBhdmFpbGFibGUgaGVpZ2h0OgotICAgICAgICAgICAgICAg
ICAgICAgICAgaGVpZ2h0MSAtPSBmbG93YWJsZV9oZWlnaHQKLSAgICAgICAgICAgICAgICAgICAg
ZWxzZToKLSAgICAgICAgICAgICAgICAgICAgICAgICMgVGhlIGNvbnRlbnQgZG9lc24ndCBmaXQg
YWZ0ZXIgdGhlIHNwbGl0OgotICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFtdCisgICAg
ICAgICAgICAgICAgaWYgZmxvd2FibGVfc3BsaXRfYXR0ZW1wdGVkOgorICAgICAgICAgICAgICAg
ICAgICAjIHRoZSBmbG93YWJsZSBzcGxpdCBtYXkgaGF2ZSBmYWlsZWQsIGJ1dCB3ZSBtYWRlIHNv
bWUgcHJvZ3Jlc3MsCisgICAgICAgICAgICAgICAgICAgICMgc28gcG9zdHBvbmUgZXZlcnl0aGlu
ZyBlbHNlIGFuZCBob3BlIGl0IGNhbiBiZSBzcGxpdC93cmFwcGVkIGxhdGVyIG9uCisgICAgICAg
ICAgICAgICAgICAgIHBvc3Rwb25lZENvbnRlbnQuYXBwZW5kKGZsb3dhYmxlKQogICAgICAgICAg
ICAgICAgIGVsaWYgdXNlZEhlaWdodCArIGZsb3dhYmxlX2hlaWdodCArIGZsb3dhYmxlLmdldFNw
YWNlQmVmb3JlKCkgPD0gaGVpZ2h0MDoKICAgICAgICAgICAgICAgICAgICAgbmV3Q2VsbENvbnRl
bnQuYXBwZW5kKGZsb3dhYmxlKQogICAgICAgICAgICAgICAgICAgICB1c2VkSGVpZ2h0ICs9IGZs
b3dhYmxlX2hlaWdodCArIGZsb3dhYmxlLmdldFNwYWNlQmVmb3JlKCkgKyBmbG93YWJsZS5nZXRT
cGFjZUFmdGVyKCkKICAgICAgICAgICAgICAgICBlbHNlOgogICAgICAgICAgICAgICAgICAgICAj
IFRoaXMgaXMgd2hlcmUgd2UgbmVlZCB0byBzcGxpdAogICAgICAgICAgICAgICAgICAgICBzcGxp
dEhlaWdodCA9IGhlaWdodDAtdXNlZEhlaWdodC1mbG93YWJsZS5nZXRTcGFjZUJlZm9yZSgpCisg
ICAgICAgICAgICAgICAgICAgIHNwbGl0cyA9IE5vbmUKICAgICAgICAgICAgICAgICAgICAgaWYg
aGFzYXR0cihmbG93YWJsZSwnX2ZpbmRTcGxpdCcpOgogICAgICAgICAgICAgICAgICAgICAgICAg
X3csX0gsIFMwLCBTMSA9IGZsb3dhYmxlLl9maW5kU3BsaXQoZ2V0YXR0cihzZWxmLCdjYW52JyxO
b25lKSx3aWR0aCxzcGxpdEhlaWdodCxtZXJnZVNwYWNlPTEsb2JqPU5vbmUsY29udGVudD1Ob25l
LHBhcmFGaXg9VHJ1ZSkKICAgICAgICAgICAgICAgICAgICAgICAgIGlmIFMwIGFuZCBTMToKQEAg
LTE0OTcsMjMgKzE0OTQsMTYgQEAgb25seSByb3dzIG1heSBiZSBzdHJpbmdzIHdpdGggdmFsdWVz
IGluIHtfU1BFQ0lBTFJPV1Mhcn0nJycpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3
Q2VsbENvbnRlbnQuYXBwZW5kKHNwbGl0c1swXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICBwb3N0cG9uZWRDb250ZW50LmFwcGVuZChzcGxpdHNbMV0pCiAgICAgICAgICAgICAgICAgICAg
IGlmIG5vdCBzcGxpdHM6Ci0gICAgICAgICAgICAgICAgICAgICAgICAjIFdlIGNvdWxkbid0IHNw
bGl0IHRoaXMgZmxvd2FibGUgYXQgdGhlIGRlc2lyZWQKLSAgICAgICAgICAgICAgICAgICAgICAg
ICMgcG9pbnQuIElmIHdlIGFscmVhZHkgaGFzIGFkZGVkIHByZXZpb3VzIHBhcmFncmFwaHMKLSAg
ICAgICAgICAgICAgICAgICAgICAgICMgdG8gdGhlIGNvbnRlbnQsIGp1c3QgYWRkIGV2ZXJ5dGhp
bmcgYWZ0ZXIgdGhlIHNwbGl0LgotICAgICAgICAgICAgICAgICAgICAgICAgIyBBbHNvIHRyeSBh
ZGRpbmcgaXQgYWZ0ZXIgdGhlIHNwbGl0IGlmIHZhbGlnbiBpc24ndCBUT1AKLSAgICAgICAgICAg
ICAgICAgICAgICAgIGlmIG5ld0NlbGxDb250ZW50IG9yIHN0eWxlLnZhbGlnbiAhPSAiVE9QIjoK
LSAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiBmbG93YWJsZV9oZWlnaHQgPD0gaGVpZ2h0
MToKLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zdHBvbmVkQ29udGVudC5hcHBl
bmQoZmxvd2FibGUpCi0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgU2hyaW5rIHRo
ZSBhdmFpbGFibGUgaGVpZ2h0OgotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWln
aHQxIC09IGZsb3dhYmxlX2hlaWdodAotICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6
Ci0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgVGhlIGNvbnRlbnQgZG9lc24ndCBm
aXQgYWZ0ZXIgdGhlIHNwbGl0OgotICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1
cm4gW10KLSAgICAgICAgICAgICAgICAgICAgICAgIGVsc2U6Ci0gICAgICAgICAgICAgICAgICAg
ICAgICAgICAgIyBXZSBjb3VsZCBub3Qgc3BsaXQgdGhpcywgc28gd2UgZmFpbDoKKyAgICAgICAg
ICAgICAgICAgICAgICAgICMgV2UgY291bGRuJ3Qgc3BsaXQgdGhpcyBmbG93YWJsZSBhdCB0aGUg
ZGVzaXJlZCBwb2ludAorICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5vdCBuZXdDZWxsQ29u
dGVudCkgYW5kIHN0eWxlLnZhbGlnbiA9PSAiVE9QIjoKKyAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAjIFRoaXMgaXMgdGhlIGZpcnN0IGZsb3dhYmxlIGluIHRoZSBjZWxsLCBhbmQgdGhlIGNl
bGwKKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGlzIHRvcC1hbGlnbmVkIC0gc2luY2Ug
c3BsaXR0aW5nIHRoZSBmbG93YWJsZSBmYWlsZWQsCisgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIyBzcGxpdHRpbmcgdGhlIGNlbGwgaGFzIGZhaWxlZC4KICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICByZXR1cm4gW10KIAotICAgICAgICAgICAgICAgICAgICBzcGxpdCA9IFRydWUKKyAg
ICAgICAgICAgICAgICAgICAgICAgICMgcG9zdHBvbmUgdGhpcyBmbG93YWJsZSwgYW5kIGhvcGUg
d2UgY2FuIHdyYXAvc3BsaXQgbGF0ZXIKKyAgICAgICAgICAgICAgICAgICAgICAgIHBvc3Rwb25l
ZENvbnRlbnQuYXBwZW5kKGZsb3dhYmxlKQorICAgICAgICAgICAgICAgICAgICBmbG93YWJsZV9z
cGxpdF9hdHRlbXB0ZWQgPSBUcnVlCiAKICAgICAgICAgICAgIHJldHVybiAodHVwbGUobmV3Q2Vs
bENvbnRlbnQpLCB0dXBsZShwb3N0cG9uZWRDb250ZW50KSkKIAotLSAKMi4zOS4xCgo=
--000000000000267298064380cbe1
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline