Skip to content

--scip overlay fails on Windows: doc.relativePath uses backslashes, never matches POSIX-normalized codeFiles paths #3

Description

@AsiaOstrich

Summary

egr index <dir> --scip <path> always fails to match any document when the .scip file was produced by a Windows-run external indexer (tested with scip-dotnet index, .NET 10 solution, Windows 11), even when <dir> is exactly the root the indexer was run against — the error message is misleading because it blames <dir>, but the real cause is a path-separator mismatch.

Root cause

In ingestScipOverlay (cli bundle, readScipIndexOrThrow → comparison logic):

const docPaths = new Set(index.documents.map((d) => d.relativePath));
const scipFiles = codeFiles.filter((f) => docPaths.has(f.path))...

codeFiles comes from egr's own walkFiles(), which normalizes paths through toPosixPath(relative(root, full)) — always forward-slash, regardless of OS.

index.documents[].relativePath, however, is taken as-is from the .scip protobuf with no normalization. scip-dotnet (the officially-recommended indexer for C#, per egr's own error message: scip-dotnet index for C#) emits Windows-style backslash-separated relative paths when run on Windows, e.g. PortaliteEnterprise.Api\Controllers\Capi\SmsController.cs.

Since the comparison is exact-string Set.has(), "Foo\Bar.cs" !== "Foo/Bar.cs" and zero documents ever match — 0/N every time, on every Windows-generated .scip file — while the tool reports:

--scip: none of the N document path(s) in "<file>" (e.g. "Foo\Bar.cs") matched any source file under "<dir>".
SCIP document paths are relative to the project root the external indexer ... was run against — pass that same root as <dir>, then retry.

This message strongly implies the fix is to change <dir>, which is a dead end — <dir> was already correct; no <dir> value fixes a separator mismatch.

Repro

  1. Windows machine, .NET solution.
  2. dotnet tool install --global scip-dotnet
  3. scip-dotnet index MySolution.sln --output my.scip --working-directory src
  4. egr index src --scip my.scip
  5. --scip: none of the 293 document path(s) ... matched any source file under "src" — even though <dir> is correct.

Confirmed workaround

Rewrite the .scip file's Document.relative_path string fields from \ to / before feeding it to egr index --scip. Since both bytes are single-byte ASCII, an exact-substring byte replacement (matching each real relative file path, not a blanket byte-swap) preserves all protobuf length prefixes, so no reserialization is needed. After patching, the overlay matched (275/293 and 252/279 documents respectively across two solutions/dirs in our repo) and egr callers <symbol> started resolving cross-file calls correctly (previously always empty on our C# codebase due to tree-sitter's lack of type info).

Suggested fix

Normalize d.relativePath (and/or f.path) with the same toPosixPath() used for codeFiles before building docPaths / doing the comparison — one line, no protobuf reserialization needed on egr's side since this only needs to happen in memory at comparison time:

const docPaths = new Set(index.documents.map((d) => toPosixPath(d.relativePath)));

Also worth improving the error message to mention path-separator mismatch as a possible cause (not just "wrong <dir>"), since as written it sends users down the wrong debugging path.

Environment

  • egr 0.9.1, Node v24.13.0, win32-x64
  • scip-dotnet 0.2.14
  • Windows 11

Related to earlier C# parsing bugs we reported in #1 and #2 — this one is in the --scip overlay path introduced since 0.9.1, not the tree-sitter parser itself.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions