rust-lang / rust-lang/rust-analyzer

scip: panics with "Invariant violation: file emitted multiple times" when one file is mounted into two targets via #[path]

Open
#23,299 2 comments 0 reactions 1 assignee View on GitHub

@moosama76 is already working on this.

Since Sep 8, 2026.

A-lsif/scip C-bug I-panic
Dominant language
Rust
Stars
16.9k
Forks
2.2k
Avg merge
1d 12h
Merged PRs (30d)
72

Description

rust-analyzer scip panics on any workspace where a single source file is reachable from more than one target via #[path]. This is a legal and reasonably common pattern for sharing helpers between integration-test targets, and it makes SCIP indexing impossible for the whole workspace.

Version

rust-analyzer 1.93.0 (254b5960 2026-01-19)
rustc 1.93.0 (254b59607 2026-01-19)
aarch64-apple-darwin

Minimal reproduction

Six files:

Cargo.toml
src/lib.rs
tests/shared/helper.rs
tests/target_a.rs
tests/target_b.rs

Cargo.toml

[package]
name = "scip-path-repro"
version = "0.1.0"
edition = "2021"

src/lib.rs

pub fn hello() -> u32 { 42 }

tests/shared/helper.rs

pub fn helper() -> u32 { 1 }

tests/target_a.rs and tests/target_b.rs — identical, both mounting the same file:

#[path = "shared"]
mod shared {
    #[path = "helper.rs"]
    pub mod helper;
}
#[test]
fn t() { assert_eq!(shared::helper::helper(), 1); }

Then:

$ rust-analyzer scip . --output out.scip
thread 'main' panicked at src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs:227:17:
Invariant violation: file emitted multiple times.

Exit 101, no index written.

Expected

tests/shared/helper.rs is one file that legitimately belongs to two crate targets. SCIP should emit it once (or once per target with distinct document identity), rather than panicking.

Notes

  • Reproduces with and without --exclude-vendored-libraries.
  • On the real workspace this was found in (single crate, 9 [[bin]], 20 examples, several integration-test targets) the panic arrives after ~115s and ~7.8 GB peak RSS, so on a large project the cost of discovering it is significant.
  • cargo test builds and runs both targets without complaint — only the SCIP writer objects.
  • The pattern is deliberate in that codebase: a second test target re-mounts a module tree verbatim via #[path] to run the same tests under a different global allocator.

Happy to test a patch.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.