[docutils:bugs] #504 errors for malformed tables do not indicate what the error is

Günter Milde via Docutils-develop <[email protected]> Thu, 18 Sep 2025 07:43:07 -0000
Newsgroups gmane.text.docutils.devel
Message-ID </p/docutils/bugs/504/2b19ca551d59ba6bb51637c4fb22067b6dcc659d.bugs@docutils.p.sourceforge.net>
This is a multi-part message in MIME format.
--===============1352185160802946082==
Content-Type: multipart/related; boundary="===============2274454002778568584=="

This is a multi-part message in MIME format.
--===============2274454002778568584==
Content-Type: multipart/alternative; boundary="===============5592783220671266123=="
MIME-Version: 1.0

--===============5592783220671266123==
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

- **status**: open-fixed --> closed-fixed
- **Comment**:

Fixed in [Docutils 0.22.1](https://pypi.org/project/docutils/0.22.1/).
Thanks again!




---

**[bugs:#504] errors for malformed tables do not indicate what the error is**

**Status:** closed-fixed
**Created:** Thu Jun 05, 2025 09:04 PM UTC by Jynn Nelson
**Last Updated:** Tue Aug 19, 2025 09:30 PM UTC
**Owner:** nobody
**Attachments:**

- [table.rst](https://sourceforge.net/p/docutils/bugs/504/attachment/table.rst) (1.1 kB; application/octet-stream)


The error messages for malformed tables are quite long and do not indicate where the error occurred. I expect docutils to point at a single line of code, and say why it was malformed. Instead it points at the whole table and just says "malformed table".

~~~
$ grep PRETTY /etc/os-release
PRETTY_NAME="Pop!_OS 22.04 LTS"
$ python -V
Python 3.10.12
$ docutils -V
docutils (Docutils 0.21.2, Python 3.10.12, on linux)
$ docutils --traceback table.rst >/dev/null
table.rst:5: (ERROR/3) Malformed table.

+-------------------------+-------------------+
| Standard Code           | Message(s)       |
+=========================+===================+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M1, indicator undefined | Illegal reference |
+-------------------------+-------------------+
| M2, Invalid combination | None              |
+-------------------------+-------------------+
~~~

Note that docutils *does*  have the information to report this bug, because I can see it in a debugger. It simply doesn't include that info in the error.

~~~
$ python -m pdb $(which docutils) --traceback table.rst
> /home/jyn/.local/bin/docutils(3)<module>()
-> import re
(Pdb) break docutils/parsers/rst/states.py:1787
Breakpoint 1 at /home/jyn/.local/lib/python3.10/site-packages/docutils/parsers/rst/states.py:1787
(Pdb) c
> /home/jyn/.local/lib/python3.10/site-packages/docutils/parsers/rst/states.py(1787)malformed_table()
-> message = 'Malformed table.'
(Pdb) up
> /home/jyn/.local/lib/python3.10/site-packages/docutils/parsers/rst/states.py(1737)isolate_grid_table()
-> messages.extend(self.malformed_table(block))
(Pdb) list
1732 	            else:
1733 	                messages.extend(self.malformed_table(block))
1734 	                return [], messages, blank_finish
1735 	        for i in range(len(block)):     # check right edge
1736 	            if len(block[i]) != width or block[i][-1] not in '+|':
1737 ->	                messages.extend(self.malformed_table(block))
1738 	                return [], messages, blank_finish
1739 	        return block, messages, blank_finish
1740 	
1741 	    def isolate_simple_table(self):
1742 	        start = self.state_machine.line_offset
(Pdb) p block[i]
'| Standard Code           | Message(s)       |'
(Pdb) p width
47
(Pdb) p len(block[i])
46
~~~


---

Sent from sourceforge.net because [email protected] is subscribed to https://sourceforge.net/p/docutils/bugs/

To unsubscribe from further messages, a project admin can change settings at https://sourceforge.net/p/docutils/admin/bugs/options.  Or, if this is a mailing list, you can unsubscribe from the mailing list.
--===============5592783220671266123==
MIME-Version: 1.0
Content-Type: text/html; charset="us-ascii"
Content-Transfer-Encoding: 7bit

<div class="markdown_content"><ul>
<li><strong>status</strong>: open-fixed --&gt; closed-fixed</li>
<li><strong>Comment</strong>:</li>
</ul>
<p>Fixed in <a class="" href="https://pypi.org/project/docutils/0.22.1/" rel="nofollow">Docutils 0.22.1</a>.<br/>
Thanks again!</p>
<hr/>
<p><strong><a class="alink strikethrough" href="https://sourceforge.net/p/docutils/bugs/504/">[bugs:#504]</a> errors for malformed tables do not indicate what the error is</strong></p>
<p><strong>Status:</strong> closed-fixed<br/>
<strong>Created:</strong> Thu Jun 05, 2025 09:04 PM UTC by Jynn Nelson<br/>
<strong>Last Updated:</strong> Tue Aug 19, 2025 09:30 PM UTC<br/>
<strong>Owner:</strong> nobody<br/>
<strong>Attachments:</strong></p>
<ul>
<li><a class="" href="https://sourceforge.net/p/docutils/bugs/504/attachment/table.rst">table.rst</a> (1.1 kB; application/octet-stream)</li>
</ul>
<p>The error messages for malformed tables are quite long and do not indicate where the error occurred. I expect docutils to point at a single line of code, and say why it was malformed. Instead it points at the whole table and just says "malformed table".</p>
<div class="codehilite"><pre><span></span><code><span class="c">$ grep PRETTY /etc/os</span><span class="nb">-</span><span class="c">release</span>
<span class="c">PRETTY_NAME="Pop!_OS 22</span><span class="nt">.</span><span class="c">04 LTS"</span>
<span class="c">$ python </span><span class="nb">-</span><span class="c">V</span>
<span class="c">Python 3</span><span class="nt">.</span><span class="c">10</span><span class="nt">.</span><span class="c">12</span>
<span class="c">$ docutils </span><span class="nb">-</span><span class="c">V</span>
<span class="c">docutils (Docutils 0</span><span class="nt">.</span><span class="c">21</span><span class="nt">.</span><span class="c">2</span><span class="nt">,</span><span class="c"> Python 3</span><span class="nt">.</span><span class="c">10</span><span class="nt">.</span><span class="c">12</span><span class="nt">,</span><span class="c"> on linux)</span>
<span class="c">$ docutils </span><span class="nb">--</span><span class="c">traceback table</span><span class="nt">.</span><span class="c">rst </span><span class="nv">&gt;</span><span class="c">/dev/null</span>
<span class="c">table</span><span class="nt">.</span><span class="c">rst:5: (ERROR/3) Malformed table</span><span class="nt">.</span>

<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| Standard Code           | Message(s)       |</span>
<span class="nb">+</span><span class="c">=========================</span><span class="nb">+</span><span class="c">===================</span><span class="nb">+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M1</span><span class="nt">,</span><span class="c"> indicator undefined | Illegal reference |</span>
<span class="nb">+-------------------------+-------------------+</span>
<span class="c">| M2</span><span class="nt">,</span><span class="c"> Invalid combination | None              |</span>
<span class="nb">+-------------------------+-------------------+</span>
</code></pre></div>

<p>Note that docutils <em>does</em>  have the information to report this bug, because I can see it in a debugger. It simply doesn't include that info in the error.</p>
<div class="codehilite"><pre><span></span><code><span class="err">$</span> <span class="n">python</span> <span class="o">-</span><span class="n">m</span> <span class="n">pdb</span> <span class="err">$</span><span class="p">(</span><span class="n">which</span> <span class="n">docutils</span><span class="p">)</span> <span class="o">--</span><span class="n">traceback</span> <span class="n">table</span><span class="o">.</span><span class="n">rst</span>
<span class="o">&gt;</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">jyn</span><span class="o">/.</span><span class="n">local</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">docutils</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span><span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span><span class="p">()</span>
<span class="o">-&gt;</span> <span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="k">break</span> <span class="n">docutils</span><span class="o">/</span><span class="n">parsers</span><span class="o">/</span><span class="n">rst</span><span class="o">/</span><span class="n">states</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">1787</span>
<span class="n">Breakpoint</span> <span class="mi">1</span> <span class="n">at</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">jyn</span><span class="o">/.</span><span class="n">local</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">python3</span><span class="mf">.10</span><span class="o">/</span><span class="n">site</span><span class="o">-</span><span class="n">packages</span><span class="o">/</span><span class="n">docutils</span><span class="o">/</span><span class="n">parsers</span><span class="o">/</span><span class="n">rst</span><span class="o">/</span><span class="n">states</span><span class="o">.</span><span class="n">py</span><span class="p">:</span><span class="mi">1787</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="n">c</span>
<span class="o">&gt;</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">jyn</span><span class="o">/.</span><span class="n">local</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">python3</span><span class="mf">.10</span><span class="o">/</span><span class="n">site</span><span class="o">-</span><span class="n">packages</span><span class="o">/</span><span class="n">docutils</span><span class="o">/</span><span class="n">parsers</span><span class="o">/</span><span class="n">rst</span><span class="o">/</span><span class="n">states</span><span class="o">.</span><span class="n">py</span><span class="p">(</span><span class="mi">1787</span><span class="p">)</span><span class="n">malformed_table</span><span 
 class="p">()</span>
<span class="o">-&gt;</span> <span class="n">message</span> <span class="o">=</span> <span class="s1">'Malformed table.'</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="n">up</span>
<span class="o">&gt;</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">jyn</span><span class="o">/.</span><span class="n">local</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">python3</span><span class="mf">.10</span><span class="o">/</span><span class="n">site</span><span class="o">-</span><span class="n">packages</span><span class="o">/</span><span class="n">docutils</span><span class="o">/</span><span class="n">parsers</span><span class="o">/</span><span class="n">rst</span><span class="o">/</span><span class="n">states</span><span class="o">.</span><span class="n">py</span><span class="p">(</span><span class="mi">1737</span><span class="p">)</span><span class="n">isolate_grid_table</span><sp
 an class="p">()</span>
<span class="o">-&gt;</span> <span class="n">messages</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">malformed_table</span><span class="p">(</span><span class="n">block</span><span class="p">))</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="nb">list</span>
<span class="mi">1732</span>                <span class="k">else</span><span class="p">:</span>
<span class="mi">1733</span>                    <span class="n">messages</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">malformed_table</span><span class="p">(</span><span class="n">block</span><span class="p">))</span>
<span class="mi">1734</span>                    <span class="k">return</span> <span class="p">[],</span> <span class="n">messages</span><span class="p">,</span> <span class="n">blank_finish</span>
<span class="mi">1735</span>            <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">)):</span>     <span class="c1"># check right edge</span>
<span class="mi">1736</span>                <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">!=</span> <span class="n">width</span> <span class="ow">or</span> <span class="n">block</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="s1">'+|'</span><span class="p">:</span>
<span class="mi">1737</span> <span class="o">-&gt;</span>                 <span class="n">messages</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">malformed_table</span><span class="p">(</span><span class="n">block</span><span class="p">))</span>
<span class="mi">1738</span>                    <span class="k">return</span> <span class="p">[],</span> <span class="n">messages</span><span class="p">,</span> <span class="n">blank_finish</span>
<span class="mi">1739</span>            <span class="k">return</span> <span class="n">block</span><span class="p">,</span> <span class="n">messages</span><span class="p">,</span> <span class="n">blank_finish</span>
<span class="mi">1740</span>    
<span class="mi">1741</span>        <span class="k">def</span><span class="w"> </span><span class="nf">isolate_simple_table</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="mi">1742</span>            <span class="n">start</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">state_machine</span><span class="o">.</span><span class="n">line_offset</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="n">p</span> <span class="n">block</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="s1">'| Standard Code           | Message(s)       |'</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="n">p</span> <span class="n">width</span>
<span class="mi">47</span>
<span class="p">(</span><span class="n">Pdb</span><span class="p">)</span> <span class="n">p</span> <span class="nb">len</span><span class="p">(</span><span class="n">block</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="mi">46</span>
</code></pre></div>

<hr/>
<p>Sent from sourceforge.net because [email protected] is subscribed to <a href="https://sourceforge.net/p/docutils/bugs/">https://sourceforge.net/p/docutils/bugs/</a></p>
<p>To unsubscribe from further messages, a project admin can change settings at <a href="https://sourceforge.net/p/docutils/admin/bugs/options.">https://sourceforge.net/p/docutils/admin/bugs/options.</a>  Or, if this is a mailing list, you can unsubscribe from the mailing list.</p></div>
--===============5592783220671266123==--

--===============2274454002778568584==--


--===============1352185160802946082==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


--===============1352185160802946082==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline