Skip to content

fix: ensure listItem and taskItem always start with paragraph + schema validation#3663

Open
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1770285855-fix-listitem-content
Open

fix: ensure listItem and taskItem always start with paragraph + schema validation#3663
devin-ai-integration[bot] wants to merge 2 commits intomainfrom
devin/1770285855-fix-listitem-content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Feb 5, 2026

Summary

Fixes #3640 - "Invalid content for node listItem" error.

The ProseMirror schema requires listItem content to be paragraph block* (must start with a paragraph, followed by zero or more blocks). The previous markdown-to-tiptap conversion could produce listItem nodes that started with nested lists (bulletList, orderedList), which violates the schema and causes validation errors.

Changes:

  • Added ensure_starts_with_paragraph() helper in crates/tiptap/src/from_md.rs
  • Applied fix to both convert_list_item() and convert_task_item()
  • Added test cases to verify the fix

Updates since last revision

Added a Rust-side schema validation module (crates/tiptap/src/validate.rs) to be fundamentally safer against this class of bugs. Instead of only patching individual cases, the validate_tiptap_json() function encodes ProseMirror content rules for all node types:

Node Content spec
doc block+
listItem / taskItem paragraph block*
bulletList / orderedList listItem+
taskList taskItem+
blockquote block+
paragraph / heading inline*
codeBlock text*

Added 20+ schema validation tests that run diverse markdown inputs (nested lists, empty list items, blockquotes with lists, deeply nested structures, etc.) through md_to_tiptap_json and validate the output. Any future converter change that produces schema-invalid JSON will be caught by these tests.

Review & Testing Checklist for Human

  • Verify is_block_type / is_inline_type lists match your actual tiptap extensions — these are hardcoded in validate.rs and won't auto-update if you add new node types to the editor. image intentionally appears in both lists (tiptap treats it as block and inline depending on context).
  • Test with the actual problematic content from issue [BUG] Invalid content for node listitem #3640 — Rust tests pass but this hasn't been verified against the real frontend validation error
  • Check UI rendering of list items — inserting empty paragraphs before nested lists could affect how list items display in the editor
  • Test markdown roundtrip — Verify that md → tiptap → md conversion doesn't lose data or produce unexpected results with the new empty paragraphs

Recommended test plan:

  1. Load a note that previously triggered the "Invalid content for node listItem" error
  2. Verify the error no longer occurs
  3. Create new lists with nested content and verify they save/load correctly

Notes

This fixes issue #3640 where the Tiptap schema validation fails with
'Invalid content for node listItem' error.

The ProseMirror schema requires listItem content to be 'paragraph block*',
meaning it must start with a paragraph. The previous implementation could
produce listItems that started with nested lists (bulletList, orderedList)
which violates the schema.

Changes:
- Add ensure_starts_with_paragraph() helper function
- Apply to convert_list_item() and convert_task_item()
- Add test cases to verify the fix

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for hyprnote-storybook canceled.

Name Link
🔨 Latest commit b3ed743
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/698565ef966e0100077f9283

@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit b3ed743
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/698565ef970efd0008a5fbaf
😎 Deploy Preview https://deploy-preview-3663--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Encodes ProseMirror content rules (doc: block+, listItem: paragraph block*,
taskItem: paragraph block*, blockquote: block+, etc.) in a Rust validate_tiptap_json()
function. Adds 20+ tests that run diverse markdown inputs through md_to_tiptap_json
and validate the output against these rules, catching any schema violation automatically.

Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
@devin-ai-integration devin-ai-integration bot changed the title fix: ensure listItem and taskItem always start with paragraph fix: ensure listItem and taskItem always start with paragraph + schema validation Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Invalid content for node listitem

1 participant