rust-lang/cargo · error

found an override with a non-locked list

Error message

found an override with a non-locked list

What it means

When a path override is active, the underlying source must return exactly one summary (the locked candidate). After querying, the registry checks `if n > 1` (registry.rs:801) and bails: multiple summaries mean the source list is not locked, so the override is ambiguous. This protects against overrides pointing at sources with several matching versions.

Solutions

  1. Run `cargo update <dep>` to re-lock the dependency to a single version.
  2. Ensure the override path/git source contains exactly one matching version.
  3. Delete the lock file and regenerate it with `cargo generate-lockfile`.

Example fix

# before: override path has multiple versions, lock stale
# (run:)
# cargo generate-lockfile && cargo build

# after: lock pins a single version, override resolves cleanly
Defensive patterns

Strategy: retry

Validate before calling

// Ensure override source yields a single version
fn override_is_locked(versions: &[semver::Version]) -> bool {
    versions.len() == 1
}

Try / catch

// on "found an override with a non-locked list":
//   cargo generate-lockfile && cargo build

Prevention

When it happens

Trigger: A path override is set for a dependency, and the overridden source returns more than one version summary during the query callback (incrementing `n` past 1).

Common situations: Overriding a path that contains multiple versions of the crate. A lock file that no longer pins the override to a single version. Source index changes that surface additional summaries.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11). Data as JSON: /api/errors/2de7bd13e4a932b5. Report an issue: GitHub.

Appendix: source

Thrown at src/workspace/registry.rs:815

                    return Err(anyhow::anyhow!("found patches and a path override"));
                }
                let mut n = 0;
                let mut to_warn = None;
                let callback = &mut |summary| {
                    n += 1;
                    match summary {
                        IndexSummary::Candidate(summary)
                        | IndexSummary::Yanked(summary)
                        | IndexSummary::Offline(summary)
                        | IndexSummary::Unsupported(summary, _)
                        | IndexSummary::Invalid(summary) => {
                            to_warn = Some(summary);
                        }
                    }
                };
                query_with_context(&*source, dep, kind, callback).await?;
                if n > 1 {
                    return Err(anyhow::anyhow!("found an override with a non-locked list"));
                }
                if let Some(to_warn) = to_warn {
                    self.warn_bad_override(&override_summary, &to_warn)?;
                }
                let override_summary = self.lock(override_summary);
                f(IndexSummary::Candidate(override_summary));
            }
        }

        Ok(())
    }

    fn describe_source(&self, id: SourceId) -> String {
        match self.sources.borrow().get(id) {
            Some(src) => src.describe(),
            None => id.to_string(),
        }
    }

View on GitHub (pinned to 98a09e7e7d)