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):
- **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):
- **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, 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:
- Toggle Preview. The document ends early — no error, no visual seam, no scrollbar hint.
- Type into the last visible paragraph. The text appears normally.
- Cmd-S. The save is accepted: no warning, no leftover dirty indicator.
- 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:
// 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
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)