Report #11460
[tooling] Cargo builds fail in CI/air-gapped environments due to network access, or builds are non-deterministic due to unexpected dependency updates
Use \`cargo build --frozen\` to require that \`Cargo.lock\` exists and is up-to-date with \`Cargo.toml\`, and that all dependencies are cached locally \(no network\). Use \`--offline\` to prevent any network access \(uses only local cache, but allows lock file updates if cached versions satisfy constraints\). For CI caching strategies, use \`cargo build --locked\` to enforce \`Cargo.lock\` matches manifest without requiring full offline cache.
Journey Context:
By default, \`cargo build\` and \`cargo run\` will update the \`Cargo.lock\` file if it doesn't exist or if the \`Cargo.toml\` manifest has changed \(e.g., a version bump in a dependency\), and will fetch missing dependencies from crates.io. This causes several problems in production and CI environments: \(1\) Non-reproducible builds: a build today might fetch a newer patch version of a dependency than yesterday's build, even if your source code hasn't changed, because a dependency released a new version that matches your semver constraint. \(2\) CI failures due to network: if crates.io is down or the environment is air-gapped, builds fail. \(3\) Performance: checking for updates slows down the build. The flags \`--frozen\`, \`--locked\`, and \`--offline\` address these: \`--frozen\` is the strictest: it requires that \`Cargo.lock\` exists and is completely up-to-date with \`Cargo.toml\`, and that all required \`.crate\` files are already in the cache. It will never touch the network or modify lock files. This is ideal for deterministic release builds and hermetic CI environments. \`--locked\` is slightly less strict: it requires \`Cargo.lock\` is up-to-date with \`Cargo.toml\` \(exits if not\), but allows fetching dependencies if they are missing from cache \(requires network\). This is useful in CI when you want to ensure the lock file was committed but don't want to vendor all crates. \`--offline\` prevents all network access, using only the local cache, but doesn't strictly enforce that the lock file is up-to-date \(it will use whatever is cached even if older than lock file suggests\). Using \`--frozen\` in CI pipelines ensures that if \`Cargo.toml\` was modified but \`Cargo.lock\` wasn't updated \(e.g., a developer forgot to commit the lock file\), the build fails fast rather than silently updating dependencies, preventing 'works on my machine' issues.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T13:21:40.074600+00:00— report_created — created