Skip to content

fix(ipynb): handle string and null cell sources in IpynbConverter#2239

Open
hsusul wants to merge 1 commit into
microsoft:mainfrom
hsusul:fix-ipynb-string-source-title
Open

fix(ipynb): handle string and null cell sources in IpynbConverter#2239
hsusul wants to merge 1 commit into
microsoft:mainfrom
hsusul:fix-ipynb-string-source-title

Conversation

@hsusul

@hsusul hsusul commented Jul 25, 2026

Copy link
Copy Markdown

Summary

  • Normalizes Jupyter notebook cell source field representations (str, list[str], None, or missing) in IpynbConverter.
  • Enables correct line-by-line title extraction when a notebook cell source is a single string.
  • Prevents TypeError and conversion failure when cell sources are None or missing.

Problem

According to the Jupyter notebook specification (nbformat v4), cell source fields may be represented either as a list of strings or as a single string (or None).
When source is a string (e.g., "# Title\nSome markdown"), IpynbConverter._convert() previously iterated over source_lines character-by-character ('#', ' ', ...). As a result, heading detection (line.startswith("# ")) never matched, failing to extract the document title.
Additionally, if a cell source is None or missing, "".join(None) raised a TypeError wrapped in a FileConversionException, causing MarkItDown to crash or fall back to raw plain text output.
Furthermore, if metadata in the notebook JSON is null, notebook_content.get("metadata", {}).get("title", title) raised an AttributeError.

Root cause

IpynbConverter._convert() assumed cell.get("source", []) is always a list of line strings, without normalizing string or None values.

Fix

  • Added _get_source_lines(source: Any) -> list[str] helper method to normalize cell sources (str, list, None) into a list of line strings with preserved line endings.
  • Used _get_source_lines() across all cell types (markdown, code, raw).
  • Updated metadata dict access to safely handle metadata: null.
  • Added unit test test_ipynb_converter_string_and_none_source covering string, list, and None cell sources.

Testing

  • pytest packages/markitdown/tests/test_module_misc.py -k test_ipynb_converter_string_and_none_source — PASS
  • pytest packages/markitdown/tests/test_module_vectors.py — PASS (109 passed)
  • git diff --check — PASS (clean, no trailing whitespace)

Compatibility

100% backward compatible. All existing tests pass.

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.

1 participant