You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dockerfile grammar flags stock .NET Dockerfiles as parse_partial #1610
(also present in v0.10.3 — the release notes mention no Dockerfile grammar change)
Platform
Windows (x64)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
Unmodified Visual Studio-generated Dockerfiles are flagged parse_partial on standard lines — the exec-form ENTRYPOINT JSON array and COPY --from=<stage>. Both are stock syntax emitted by VS "Add Docker Support" for every ASP.NET project, so the flag is effectively permanent for .NET repositories: measured on a 22-repo .NET fleet, this put a persistent <name>::missed shadow row into most stores.
On its own this is only noise in check_index_coverage, but it becomes load-bearing through #1609 (any shadow row disqualifies the project from cross-repo linking), which is why I'm reporting the grammar gap rather than shrugging it off.
I expected stock Dockerfile syntax to parse cleanly — or, if partial Dockerfile coverage is by design, for Dockerfile-grammar misses not to create shadow rows.
Reproduction
Code being indexed — a dummy repo whose root Dockerfile contains:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Result: the Dockerfile is reported parse_partial, and the store's projects table gains demo::missed.
Expected: clean parse (exec-form ENTRYPOINT/CMD and COPY --from=<stage> are standard Dockerfile syntax).
Logs
(no error output — the flag only surfaces in check_index_coverage and as the ::missed shadow row)
Confirmations
I searched existing issues and this is not a duplicate.
My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
Thank you for this, and for the other two reports filed alongside it — #1609 is fixed on main and ships in v0.10.5, and #1611 reproduced exactly as you described.
This one I could not reproduce, and I want to be transparent about what I tried rather than just asking you to try again:
your 3-line Dockerfile, exactly as filed → parse_partial_count: 0, check_index_coverage returns no_recorded_issue
the full stock Visual Studio multi-stage Dockerfile (21 lines: ARG, USER $APP_UID, COPY --from=publish, exec-form ENTRYPOINT) → 0
a CRLF-line-ending variant of the same → 0
I also checked that this is a fair test of your version: internal/cbm/vendored/grammars/dockerfile and pass_infrascan.c have had no commits since v0.10.1, so the binary I tested is a valid proxy for the 0.10.2/0.10.3 behaviour you saw.
So something in the real file differs from the reduction, and it is more likely that my reproduction is missing it than that your report is wrong — your other two reports verified precisely, including one that turned out to be a genuine blocker nobody else had found.
Two things would settle it, whichever is easier:
The actual Dockerfile that triggers it (redacted as you like — the structure is what matters: line endings, a BOM, unusual RUN continuations, heredocs, non-ASCII bytes in a LABEL).
Or just the check_index_coverage output for that path — the error_ranges field gives the exact line span the parser choked on, which usually identifies the construct on its own.
No rush, and thank you for the care in all three reports.
Found it, and your reproduction was missing one byte: the file has no final newline. That is the whole trigger — not the BOM, not CRLF, not the instruction form.
I can't share the original file, so I isolated the property instead and rebuilt it from scratch. Every fixture below is synthetic, written byte-exactly from a script (an editor would silently add the newline back and hide the bug).
Minimal reproduction — two lines, LF, no trailing newline:
# write_dockerfile.pydata=b'FROM mcr.microsoft.com/dotnet/aspnet:8.0\nENTRYPOINT ["dotnet", "App.dll"]'# note: no trailing \nopen("Dockerfile", "wb").write(data)
codebase-memory-mcp cli index_repository --repo-path <dir> --mode full
-> parse_partial_count: 1
Append a single \n to the same bytes and it is 0.
Isolation matrix (each variant indexed as its own throwaway project, v0.10.4, Windows x64, release archive):
BOM
line endings
final newline
last instruction
parse_partial_count
no
LF
yes
ENTRYPOINT [...]
0
no
CRLF
yes
ENTRYPOINT [...]
0
yes
CRLF
yes
ENTRYPOINT [...]
0
yes
LF
yes
ENTRYPOINT [...]
0
no
CRLF
no
ENTRYPOINT [...]
1
yes
CRLF
no
ENTRYPOINT [...]
1
no
LF
no
ENTRYPOINT [...]
1
no
CRLF
no
WORKDIR /app
1
no
CRLF
no
ENTRYPOINT dotnet App.dll (shell form)
1
no
CRLF
no
2-line file, FROM + ENTRYPOINT [...]
1
So it is independent of the BOM, of the line-ending style, of exec-form vs shell-form, and of file length. The flagged range is always the last line, and check_index_coverage reports it as a one-line span ("kind":"parse_partial", ranges:[{start:N,end:N}] where N is that last line).
For the original file that started this report, the structural facts are: UTF-8 BOM, CRLF throughout, 25 lines, no trailing newline, no tabs, no line continuations, no heredocs, and the only non-ASCII bytes in the file are the three BOM bytes. Coverage flagged 25-25 — the unterminated line.
That also explains the shape of the false signal: it is not "this construct confused the parser", it is "the file did not end the way the grammar expects", so any Dockerfile saved without a trailing newline reports a phantom partial parse — and, until your #1609 fix, dragged that project out of cross-repo linking with it.
Confirmed — reproduced here on the first try with your byte-exact fixture:
NO trailing newline -> parse_partial_count: 1
WITH trailing newline -> parse_partial_count: 0
Same two lines, same bytes, one \n apart. You were right and my reproduction was wrong: I built the fixtures with an editor and a heredoc, both of which append the final newline silently, so every variant I tried was the terminated case. Writing them from a script, exactly as you did, is the only way to see it — that detail is the most valuable part of your report.
Your isolation matrix also settles the shape of it: independent of BOM, of CRLF vs LF, of exec-form vs shell-form, and of file length, with the flagged range always the final line. That is not "a construct confused the parser", it is "the file did not end the way the grammar expects" — so any Dockerfile saved without a trailing newline reports a phantom partial parse. Plenty of tools write files that way, so this is likely under-reported rather than rare.
And your closing observation is the one that makes this more than cosmetic:
until your #1609 fix, dragged that project out of cross-repo linking with it
That is exactly right, and it means these two issues compounded. A phantom parse_partial created a <name>::missed shadow row, and that shadow row made the project fail cross-repo validation as both source and target. So a single missing newline could silently remove an entire repository from cross-repo intelligence, with no error anywhere. #1609 is fixed on main and ships in v0.10.5, which breaks that chain — but the phantom flag itself is still wrong and still worth fixing.
Not in v0.10.5 — that release is being cut right now and I am not putting an unbisected grammar/scan change into it at the last moment. It goes straight into the next one. Now that there is a deterministic two-line reproduction the fix is tractable: the question is whether the final unterminated line should be fed to the parser with a synthetic terminator, or whether the partial-parse signal should not fire for a range that is merely unterminated at EOF. I would rather answer that with the reproduction in front of me than guess.
Thank you for going back and isolating this properly instead of just resending the file. Three reports in one night, all three verified, one of them a genuine blocker nobody else had found.
Activity
vitaliy-shatskiy commentedon Aug 14, 2026
The cross-repo validation bug this feeds into is #1609.
DeusData commentedon Aug 15, 2026
Thank you for this, and for the other two reports filed alongside it — #1609 is fixed on
mainand ships in v0.10.5, and #1611 reproduced exactly as you described.This one I could not reproduce, and I want to be transparent about what I tried rather than just asking you to try again:
parse_partial_count: 0,check_index_coveragereturnsno_recorded_issueARG,USER $APP_UID,COPY --from=publish, exec-formENTRYPOINT) →00I also checked that this is a fair test of your version:
internal/cbm/vendored/grammars/dockerfileandpass_infrascan.chave had no commits since v0.10.1, so the binary I tested is a valid proxy for the 0.10.2/0.10.3 behaviour you saw.So something in the real file differs from the reduction, and it is more likely that my reproduction is missing it than that your report is wrong — your other two reports verified precisely, including one that turned out to be a genuine blocker nobody else had found.
Two things would settle it, whichever is easier:
Dockerfilethat triggers it (redacted as you like — the structure is what matters: line endings, a BOM, unusualRUNcontinuations, heredocs, non-ASCII bytes in aLABEL).check_index_coverageoutput for that path — theerror_rangesfield gives the exact line span the parser choked on, which usually identifies the construct on its own.No rush, and thank you for the care in all three reports.
vitaliy-shatskiy commentedon Aug 15, 2026
Found it, and your reproduction was missing one byte: the file has no final newline. That is the whole trigger — not the BOM, not CRLF, not the instruction form.
I can't share the original file, so I isolated the property instead and rebuilt it from scratch. Every fixture below is synthetic, written byte-exactly from a script (an editor would silently add the newline back and hide the bug).
Minimal reproduction — two lines, LF, no trailing newline:
Append a single
\nto the same bytes and it is0.Isolation matrix (each variant indexed as its own throwaway project, v0.10.4, Windows x64, release archive):
parse_partial_countENTRYPOINT [...]ENTRYPOINT [...]ENTRYPOINT [...]ENTRYPOINT [...]ENTRYPOINT [...]ENTRYPOINT [...]ENTRYPOINT [...]WORKDIR /appENTRYPOINT dotnet App.dll(shell form)FROM+ENTRYPOINT [...]So it is independent of the BOM, of the line-ending style, of exec-form vs shell-form, and of file length. The flagged range is always the last line, and
check_index_coveragereports it as a one-line span ("kind":"parse_partial",ranges:[{start:N,end:N}]where N is that last line).For the original file that started this report, the structural facts are: UTF-8 BOM, CRLF throughout, 25 lines, no trailing newline, no tabs, no line continuations, no heredocs, and the only non-ASCII bytes in the file are the three BOM bytes. Coverage flagged
25-25— the unterminated line.That also explains the shape of the false signal: it is not "this construct confused the parser", it is "the file did not end the way the grammar expects", so any Dockerfile saved without a trailing newline reports a phantom partial parse — and, until your #1609 fix, dragged that project out of cross-repo linking with it.
DeusData commentedon Aug 15, 2026
Confirmed — reproduced here on the first try with your byte-exact fixture:
Same two lines, same bytes, one
\napart. You were right and my reproduction was wrong: I built the fixtures with an editor and a heredoc, both of which append the final newline silently, so every variant I tried was the terminated case. Writing them from a script, exactly as you did, is the only way to see it — that detail is the most valuable part of your report.Your isolation matrix also settles the shape of it: independent of BOM, of CRLF vs LF, of exec-form vs shell-form, and of file length, with the flagged range always the final line. That is not "a construct confused the parser", it is "the file did not end the way the grammar expects" — so any Dockerfile saved without a trailing newline reports a phantom partial parse. Plenty of tools write files that way, so this is likely under-reported rather than rare.
And your closing observation is the one that makes this more than cosmetic:
That is exactly right, and it means these two issues compounded. A phantom
parse_partialcreated a<name>::missedshadow row, and that shadow row made the project fail cross-repo validation as both source and target. So a single missing newline could silently remove an entire repository from cross-repo intelligence, with no error anywhere. #1609 is fixed onmainand ships in v0.10.5, which breaks that chain — but the phantom flag itself is still wrong and still worth fixing.Not in v0.10.5 — that release is being cut right now and I am not putting an unbisected grammar/scan change into it at the last moment. It goes straight into the next one. Now that there is a deterministic two-line reproduction the fix is tractable: the question is whether the final unterminated line should be fed to the parser with a synthetic terminator, or whether the partial-parse signal should not fire for a range that is merely unterminated at EOF. I would rather answer that with the reproduction in front of me than guess.
Thank you for going back and isolating this properly instead of just resending the file. Three reports in one night, all three verified, one of them a genuine blocker nobody else had found.
test(parse-coverage): free the extraction results in the #1610 tests
fix(extraction): treat trailing blanks at EOF as an absent newline, n…
fix(extraction): treat trailing blanks at EOF as an absent newline, n…
fix(extraction): treat trailing blanks at EOF as an absent newline, n…
fix(extraction): treat trailing blanks at EOF as an absent newline, n…
fix(extraction): treat trailing blanks at EOF as an absent newline, n…
fix(extraction): parse every file as if its last line were terminated (…
fix(extraction): parse every file as if its last line were terminated (…
fix(extraction): parse every file as if its last line were terminated (…
fix(extraction): parse every file as if its last line were terminated (…