# Markdown Preview silently truncates documents: numbered list with 4-space-indented bullets throws uncaught "RangeError: Invalid content for node listItem"

**URL:** <https://forum.cursor.com/t/markdown-preview-silently-truncates-documents-numbered-list-with-4-space-indented-bullets-throws-uncaught-rangeerror-invalid-content-for-node-listitem/169528>\
**Category:** Bug Reports\
**Created:** [August 26, 2026, 11:14am UTC](https://forum.cursor.com/t/markdown-preview-silently-truncates-documents-numbered-list-with-4-space-indented-bullets-throws-uncaught-rangeerror-invalid-content-for-node-listitem/169528 "2026-08-26T11:14:46Z")\
**Posts on this page:** 1\
**Showing post:** 8

<div class="post-metadata">

**Author:** ![Nico\_Greenarry](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/nico_greenarry/32/119014_2.png) [@Nico\_Greenarry](https://forum.cursor.com/u/Nico_Greenarry)\
**Post date:** [August 28, 2026, 1:00am UTC](https://forum.cursor.com/t/markdown-preview-silently-truncates-documents-numbered-list-with-4-space-indented-bullets-throws-uncaught-rangeerror-invalid-content-for-node-listitem/169528/8 "2026-08-28T01:00:50Z")

</div>

Adding three findings from a day spent bisecting this with ~30 probe files. @Andrew_Austin’s bundle-level analysis is the mechanism and I can’t improve on it — these are empirical, and the first one means the recommended workaround isn’t sufficient.

## 1. It isn’t only 4-space indentation under numbered items, and 3-space indentation doesn’t avoid it

A verified pair differing in exactly one respect. **A renders fully** (100 items, 20 KB):

```markdown
- **Item 001.** Filler prose to give this item a realistic body length...

- **Item 002.** Filler prose to give this item a realistic body length...

```

**B truncates** partway through item 020 (50 items, 21 KB):

```markdown
- **Item 001.** Filler prose to give this item a realistic body length...

  Second paragraph of item 001. Filler prose to give this item a realistic body length...

- **Item 002.** Filler prose to give this item a realistic body length...

```

Plain `-` bullets, continuation indented 2 spaces (the correct alignment), no nested bullets, no fenced blocks, no numbered items, nothing over-indented. B still truncates.

So the trigger generalizes to **any list item holding more than one block** — a second paragraph, a nested list, a blockquote, a table, or a fence. A bullet with sub-bullets is paragraph + list, so that shape qualifies too. “Indent nested bullets 3 spaces under numbered items” will leave a lot of documents still silently truncating, so I would frame the user-facing workaround as **one block per list item** : fold the item into a single paragraph, or move its rich content into a subsection and leave a link in the item.

## 2. Whether it truncates also depends on document length, which is why minimal repros are unreliable here

Two conditions have to coincide: an offending item, **and** enough length for a chunk boundary to land inside one. Neither alone does it — a 14-line file containing an offending item renders fine, and a 107 KB file with no offending item renders to its last line. The cut in my synthetic ladder landed at ~8.2 KB; in real documents it landed past 10 KB. That is consistent with the chunked `insertContentAt` calls in the stack trace: a boundary falling inside an offending item is what produces the invalid fragment, not the item’s mere presence.

I think this is also the answer to @Jens_Emmerich over on [163908](https://forum.cursor.com/t/markdown-preview-fails-to-load/163908), who found that shortening his file made the bug disappear while the structure stayed identical — the structure was not what changed, the boundary moved. Two practical consequences:

- **“It rendered last time” is worthless as evidence.** I watched an unmodified file render fully, then truncate after a mode switch, because an edit elsewhere had moved a boundary.
- **Failing to reproduce on a minimal file means nothing.** Repros need to be ~10 KB+, which is awkward in a bug report and is probably why the shape family has looked narrower than it is.

## 3. Editing inside the dropped region silently discards the edit

This is the part I would flag as severity-raising, and I do not see it in either thread. On any truncating file:

1. Toggle Preview. The document ends early — no error, no visual seam, no scrollbar hint.
2. Type into the **last visible** paragraph. The text appears normally.
3. Cmd-S. The save is accepted: no warning, no leftover dirty indicator.
4. Toggle to Markdown, or switch files and back. **The edit is gone.**

`cmp` confirms the file on disk is byte-for-byte identical, so this is not the serializer-rewrites-your-file family in 153590 / 155435 / 162540 — nothing is corrupted on disk. The editor accepts keystrokes into a region the failed insert never loaded, then throws them away, while presenting an entirely normal save.

Which is why I would second Andrew’s third suggested fix independently of the other two: **catching the conversion error and surfacing “Preview could not render the rest of this document” would prevent the data loss outright** , not just improve the diagnostics. It would also save people the afternoon I spent, because every cross-check available to a user says the document is fine — and it is. The markdown is valid, `markdown-it` / `marked` / `micromark` all parse a truncating file without complaint, and `Cmd+Shift+V` renders it perfectly. In my case a whole section of a working document had been invisible for days with no indication anything was missing.

## Finding the offending items across an existing document set

If anyone needs to de-risk a pile of docs before the fix lands, this flags a conservative superset — any list item with more than one block child:

```js
// npm i markdown-it && node find-offenders.js FILE...
const fs = require("fs"), md = require("markdown-it")({ html: true });
for (const f of process.argv.slice(2)) {
  const t = md.parse(fs.readFileSync(f, "utf8"), {});
  for (let i = 0; i < t.length; i++) {
    if (t[i].type !== "list_item_open") continue;
    let depth = 0; const blocks = [];
    for (let j = i + 1; j < t.length; j++) {
      if (t[j].type === "list_item_open") depth++;
      if (t[j].type === "list_item_close") { if (!depth) break; depth--; }
      if (!depth && t[j].level === t[i].level + 1) {
        if (/_open$/.test(t[j].type)) blocks.push(t[j].type.replace(/_open$/, ""));
        else if (["fence", "hr", "html_block", "code_block"].includes(t[j].type)) blocks.push(t[j].type);
      }
    }
    if (blocks.length > 1) console.log(`${f}:${t[i].map[0] + 1} ${blocks.join(" + ")}`);
  }
}

```

One gotcha if you adapt it: `fence` / `hr` / `html_block` / `code_block` are self-closing tokens with no `_open`, so a version matching only `*_open` misses a fenced block inside a bullet and reports the file clean.

### Version Information

```auto
Version: 3.17.21
VS Code Extension API: 1.128.0
Commit: 8f2a112cb2845a97b75fd932ea5c470579ca4060
Date: 2026-08-25T01:05:08.089Z
Build Type: Stable
OS: Darwin arm64 25.5.0 (macOS, Apple Silicon)

```

---

_[View the full topic](https://forum.cursor.com/t/markdown-preview-silently-truncates-documents-numbered-list-with-4-space-indented-bullets-throws-uncaught-rangeerror-invalid-content-for-node-listitem/169528)._
