Skip to content

SONARPY-2729 Fix crash when Jupyter notebook source arrays contain multiline strings#2294

Closed
mallory-scotton wants to merge 2 commits into
masterfrom
ms/SONARPY-4327
Closed

SONARPY-2729 Fix crash when Jupyter notebook source arrays contain multiline strings#2294
mallory-scotton wants to merge 2 commits into
masterfrom
ms/SONARPY-4327

Conversation

@mallory-scotton

@mallory-scotton mallory-scotton commented Jul 16, 2026

Copy link
Copy Markdown
Member

SONARPY-2729

Analysis crashed with IllegalStateException: No IPythonLocation found for line N on notebooks where "source" was an array and one of its entries
contained embedded newlines. That's valid per the ipynb schema, but
IpynbNotebookParser.parseSourceArray counted every array entry as exactly
one line. An entry spanning several lines only added a single entry to the
line-location map, so the map and the generated source drifted apart -
and once the parser reached a line number the map didn't have, it threw.

Fixed by pulling the per-line splitting logic already used for plain-string
"source" values out into a shared helper, then reusing it for array entries
that contain embedded newlines. Single-line entries take the exact same
path as before.

I added notebook_multiline_string_in_array.ipynb to reproduce the reported
payload, a unit test in IpynbNotebookParserTest checking the location map
gets one entry per line, and an end-to-end test in
IpynbNotebookParserScannerTest that runs the real IPythonTreeMaker/
TokenEnricher path that used to throw. Full python-frontend suite and
the notebook tests in python-commons both pass.

Green build: https://github.com/SonarSource/sonar-python/actions/runs/29499453281/job/87624388023

…urce arrays

The ipynb JSON schema allows a "source" array entry to contain embedded
newlines - basically several Python lines packed into one array item. The
parser assumed every entry was exactly one line, so an entry like that
knocked the generated source out of sync with its line-location map and
blew up with "No IPythonLocation found for line N" once the enricher hit
a line the map didn't know about.

Pulled the per-line splitting logic already used for plain-string "source"
values into a shared helper and reused it for array entries with embedded
newlines, so each embedded line gets its own map entry again.
Comment thread python-frontend/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java Outdated
…a trailing newline

Caught in review: a "source" array element with embedded newlines but no
trailing newline (e.g. ["a\nb", "c"]) gets glued onto the next element on
the same physical line, but each one still got its own locationMap entry.
One entry too many for the actual line count, so every location after it
quietly drifts instead of crashing. Turns out plain, non-multiline array
elements without a trailing newline had this exact problem already - my
fix just carried it into the new code path.

Now track whether the previous array element ended with a newline, and
only give an element its own locationMap entry when it's actually starting
a fresh physical line. One that continues an unterminated line just gets
appended as plain text.
@gitar-bot

gitar-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 resolved / 1 findings

Refactors the source array parser to correctly map multiline strings by sharing existing splitting logic, resolving the location drift and crash issues. Comprehensive unit and end-to-end tests verify the fix.

✅ 1 resolved
Edge Case: Multiline non-last array element without trailing newline misaligns location map

📄 python-frontend/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java:277-291 📄 python-frontend/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java:320-334
In addSourceArrayElement, a source-array element that contains embedded newlines but does NOT end with "
" (e.g. ["a
b", "c"]) is concatenated to the next element as "a
bc" (2 physical lines), yet each split line calls addLineToSource, which increments the aggregated line counter and adds a locationMap entry. This produces one more location entry than there are physical lines, so subsequent tokens on the joined line (and the cell delimiter) resolve to the wrong IPythonLocation (wrong column), producing off positions rather than a crash. The common case (elements ending in "
", or a single multiline element as in the added test) is handled correctly; only mid-array multiline elements lacking a trailing newline drift. Consider not incrementing the line counter for the final split line when the element has no trailing newline (i.e. let the next element continue the same physical line), or add a regression test for the ["a
b","c"] shape.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@mallory-scotton mallory-scotton changed the title SONARPY-4327 Fix crash when Jupyter notebook source arrays contain multiline strings SONARPY-2729 Fix crash when Jupyter notebook source arrays contain multiline strings Jul 16, 2026
@gitar-bot

gitar-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 resolved / 1 findings

Refactors the source array parser to correctly map multiline strings by sharing existing splitting logic, resolving the location drift and crash issues. Comprehensive unit and end-to-end tests verify the fix.

✅ 1 resolved
Edge Case: Multiline non-last array element without trailing newline misaligns location map

📄 python-frontend/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java:277-291 📄 python-frontend/src/main/java/org/sonar/plugins/python/IpynbNotebookParser.java:320-334
In addSourceArrayElement, a source-array element that contains embedded newlines but does NOT end with "
" (e.g. ["a
b", "c"]) is concatenated to the next element as "a
bc" (2 physical lines), yet each split line calls addLineToSource, which increments the aggregated line counter and adds a locationMap entry. This produces one more location entry than there are physical lines, so subsequent tokens on the joined line (and the cell delimiter) resolve to the wrong IPythonLocation (wrong column), producing off positions rather than a crash. The common case (elements ending in "
", or a single multiline element as in the added test) is handled correctly; only mid-array multiline elements lacking a trailing newline drift. Consider not incrementing the line counter for the final split line when the element has no trailing newline (i.e. let the next element continue the same physical line), or add a regression test for the ["a
b","c"] shape.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@mallory-scotton
mallory-scotton deleted the ms/SONARPY-4327 branch July 16, 2026 13:39
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