Repository navigation
Description
Problem
A published post created/updated through the CLI can render normally and remain valid in Substack's primary rich-text editor, yet make the browser edit screen unstable or crash.
Verified reproduction: https://rareinsights.substack.com/p/death-by-donation-a-repugnant-transaction (post ID 210551946). The public page is healthy, but the authenticated published-post editor logs:
Editor content error encountered: Error: [tiptap error]: Invalid JSON content
RangeError: Unknown node type: image
Differential diagnosis
Confirmed
The published-post edit screen mounts two visible Tiptap editors:
- The primary editor accepts the complete stored post JSON without an error.
- A secondary restricted editor exposes only
doc,paragraph,text, andhardBreak, with basic link/bold/italic marks, but receives the full rich body.
The secondary editor rejects rich nodes present in the post:
image(first observed failure)headingblockquoteorderedList/bulletListvialistItem
It also renders a second, very long document tree beside the primary editor. In the reproduction, the primary document was approximately 15,434 px tall and the secondary copy approximately 11,170 px tall. The schema exception plus duplicated DOM is the leading explanation for browser-tab instability.
Ruled out for this post
- corrupted or malformed ProseMirror JSON
- invalid content in Substack's full editor schema
- excessive individual string/node size
- duplicate node IDs
- broken image URLs or failed asset requests
- repository-relative reader links
- public-page HTTP, console, or page errors
The body is about 51.5 KB / 536 JSON objects and all three images load.
Related but distinct compatibility defect
A scheduled control post containing a table fails in the primary editor with:
RangeError: Unknown node type: tableHeader
This is a genuine CLI/editor schema-compatibility problem and should not be conflated with the published-post secondary-editor defect.
Remaining uncertainty
The secondary editor's intended Substack function is not established. This may be a Substack regression, an undocumented published-revision representation constraint, or a post shape that triggers an otherwise latent editor bug. The CLI should therefore diagnose and contain the failure without claiming ownership of Substack's UI internals.
Detection options
A. Static capability profiles (recommended baseline)
Validate generated nodes and marks against versioned profiles:
- full draft editor profile
- restricted auxiliary editor profile
- published-revision profile
Report the first incompatible node with its JSON path and all incompatible-node counts.
Trade-off: deterministic and fast, but profiles can drift when Substack changes its private editor schema.
B. Authenticated disposable-editor canary
Create or update a non-public canary, open the authenticated edit route, capture Tiptap errors, mounted editor schemas, DOM duplication, and page stability, then delete/restore the canary.
Trade-off: detects upstream drift but is slower, authentication-dependent, potentially rate-limited, and must never perform unconfirmed publication.
C. Stored-post round-trip inspection
After create/update, retrieve the post and compare draft_body, published body, metadata, and node inventory; classify published-revision risk before reporting success.
Trade-off: catches transport differences but cannot alone prove the browser editor will mount safely.
D. Payload complexity guardrails
Record body bytes, node count/depth, image/list/table counts, and estimated duplicated DOM cost.
Trade-off: useful diagnostics, not a substitute for schema validation; thresholds risk false positives.
Resolution options
1. Fail closed on known incompatible nodes for editable published revisions
Reject or require explicit override when a target profile cannot represent the body.
Benefit: safest and transparent.
Cost: blocks otherwise publishable rich posts when only Substack's auxiliary editor is defective.
2. Normalize only unsupported structures
Examples: convert tables to accessible Markdown/HTML-safe lists; preserve headings/images for the full editor; produce a paragraph-safe auxiliary representation only if the API has a distinct supported field.
Benefit: retains most formatting.
Cost: lossy and unsafe unless the secondary representation is an actual supported API concept.
3. Editor-native round trip
Serialize through the exact schema discovered from the authenticated primary editor, then verify the resulting published-revision screen.
Benefit: strongest compatibility signal.
Cost: coupled to private implementation details and still may not control the secondary editor.
4. CLI-only update fallback
When the browser editor is known unsafe, permit update-in-place through the CLI and emit a durable warning/receipt.
Benefit: immediate operational continuity.
Cost: workaround only; users remain unable to use Substack's browser editor.
5. Upstream escalation with minimal reproducer
Provide Substack a privacy-safe fixture containing one heading, image, blockquote, and list that the full editor accepts but the secondary editor rejects.
Benefit: targets the actual UI defect.
Cost: external resolution and timing are outside this project's control.
Recommendation
Implement layered protection:
- Add static full/restricted/published-revision schema profiles and precise JSON-path diagnostics.
- Treat tables unsupported by the primary editor as a hard error unless explicitly normalized.
- Treat secondary-editor incompatibility as a prominent published-editability risk, not silent success.
- Add an authenticated disposable canary to the compatibility matrix, with rate-limit, CAPTCHA/2FA, cleanup, and no-publication boundaries.
- Preserve CLI update-in-place as a documented contingency.
- Produce a minimal upstream reproduction and avoid destructive rewriting until Substack's secondary editor contract is understood.
Acceptance criteria
- A fixture containing images/headings/lists/blockquote is valid for the full profile and reports exact incompatibilities for the restricted profile.
- A table fixture reports
tableHeaderincompatibility before any live write. - Create/update receipts distinguish public rendering, primary-editor validity, secondary-editor/editability risk, and live browser verification.
- Authenticated canary tests never publish or email without explicit confirmation and clean up deterministically.
- Rate limits, auth expiry, CAPTCHA/2FA, upstream schema drift, and cleanup failure have explicit stop conditions.
- Documentation describes CLI-only update as a contingency, not a fix.
- A privacy-safe upstream reproduction fixture is generated.
Scope boundary
Planning and diagnostics must not silently modify published content, strip rich structures, or claim Substack UI compatibility without an authenticated verification receipt.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Activity
edithatogo commentedon Aug 11, 2026
Additional live evidence from 2026-08-11:
draft createcorrectly resolved the existing published mapping (210551946) and built an update-in-place plan preserving slug and section./api/v1/handle/optionsno longer matched the expected shape (status: schema-drift, browser fallback required). This is a separate transport-preflight failure and should be covered by contingencies in this issue.Editor content error encountered: [tiptap error]: Invalid JSON content.HTTP 200), and the normalUpdate→Update nowUI successfully revised the live post without changing its slug, section, headings, lists or images.This further supports keeping four states separate: API preflight compatibility, stored-draft update success, public revision success, and browser edit-screen compatibility.
[-]Detect and prevent Substack published-post editor schema crashes[/-][+]T19-01 Published-post editor schema compatibility and crash containment[/+]edithatogo commentedon Aug 12, 2026
Season 1 incremental audit — 2026-08-12
The eight-post live audit confirms the existing differential diagnosis and adds a complete bounded corpus.
Invalid JSON contentimagetableHeader(7)tableHeader(7)tableHeader(4)tableHeader(4)tableHeader(8)tableHeader(11)Directly reproduced console signatures include:
The ME-002 body is not empty or lost: authenticated
GET /api/v1/drafts/210552983returns HTTP 200 and a 46,028-byte parseabledraft_body. The editor fails while deserializing it.Updated differential diagnosis
tableHeader, but the current Substack editor schema rejects that node.Immediate operational containment
For the six numbered essays, normalize tables into accessible labelled bullet lists, update the same draft IDs in place, preserve schedules and metadata, then verify both the authenticated detail endpoint and browser editor. Do not change CLI runtime for this remediation.
The pilot requires its separate rich/published-editor containment route and should not be “fixed” by globally stripping images, headings or lists.
Recommendation
Keep the existing layered plan. Elevate primary-editor
tableHeaderdetection to a hard pre-write failure; add exact JSON paths and counts to receipts; test the authenticated editor after update; retain selective normalization as an explicit, auditable contingency. Public-page success and HTTP-200 draft retrieval must not count as browser-editability success.edithatogo commentedon Aug 12, 2026
Season 1 operational remediation outcome — 2026-08-12
The six numbered essays were normalized in place from table nodes to accessible labelled lists. Authenticated draft-detail verification shows:
tableHeadernodes before remediation;tableand zerotableHeadernodes afterward;The CLI runtime was not changed.
Important residual finding
ME-001 still raises Substack's generic Tiptap
Invalid JSON contentalert after all table nodes are removed. Its remaining rich shape includes an inline image, headings and list nodes. This aligns the scheduled-post corpus with the separate published-pilot/auxiliary-editor failure already documented in #550.Therefore the Season 1 corpus exposes two stacked compatibility failures:
tableHeaderincompatibility, now operationally removed from all six essays; andFlattening all rich nodes to paragraphs would probably restore browser editability, but would remove inline illustrations, headings, semantic lists and blockquotes. That is a destructive publication-design trade-off, not a safe automatic repair.
Recommendation
feat(editor-compatibility): implement T19-01 published-post schema co…
edithatogo commentedon Sep 6, 2026
Completed via PR #601. Track T19-01 published-post editor schema compatibility and crash containment implemented across all 5 phases.
chore(conductor): archive completed Track T19-01 and Phase P19 (#602)