htmlToMarkdown() crashes on some valid HTML markup.
Failing examples
import { htmlToMarkdown } from 'obsidian';
// Crash: empty table
htmlToMarkdown('<table></table>')
// Crash: table with empty tbody only
htmlToMarkdown('<table><tbody></tbody></table>')
// Crash: table with empty thead only
htmlToMarkdown('<table><thead></thead></table>')
// Crash: table with whitespace but no <tr>
htmlToMarkdown('<table><tbody> </tbody></table>')
// Crash: table with nested divs but no <tr>
htmlToMarkdown('<table><tbody><div>text</div></tbody></table>')
all of them are failing with
Uncaught TypeError: Cannot read properties of undefined (reading 'cells')
at Object.replacement (app.js:1:1535239)
at k.D (turndown.js:2:9605)
at turndown.js:2:9264
at NodeList.reduce (<anonymous>)
at k.b (turndown.js:2:9113)
at k.turndown (turndown.js:2:10124)
at Module.yP (app.js:1:1533581)
at <anonymous>:1:20
Semi-working examples
If the table has some rows, even semantically incorrect HTML is still parsed. Not to real markdown tables, but at least, it doesn’t crash.
htmlToMarkdown('<table><tbody></tbody><tbody><tr><td>x</td></tr></tbody></table>');
Root cause
The bundled turndown GFM tables plugin accesses node.rows[0].cells without checking that node.rows[0] exists. Any <table> element with zero <tr> descendants triggers this.
Real-world impact
Discovered in https://github.com/mnaoumov/obsidian-email-to-vault/issues/3 when trying to use htmlToMarkdown() to convert email HTML to markdown. Email HTML commonly uses layout tables (role="presentation") with empty elements.
Workaround
Strip empty table sections from HTML before passing to htmlToMarkdown():
const doc = new DOMParser().parseFromString(html, 'text/html');
for (const table of doc.querySelectorAll('table')) {
if (!table.querySelector('tr')) {
table.remove();
}
}
htmlToMarkdown(doc.body.innerHTML);
Environment
SYSTEM INFO:
Obsidian version: 1.12.7
Installer version: 1.12.7
Operating system: Windows 11 Pro 10.0.26200
Login status: logged in
Language: en
Catalyst license: vip
Insider build toggle: on
Live preview: on
Base theme: adapt to system
Community theme: none
Snippets enabled: 0
Restricted mode: off
Plugins installed: 0
Plugins enabled: 0
RECOMMENDATIONS:
none