FuelLabs/sway · warning
lock file did not exist
Error message
lock file did not exist
What it means
Recorded in BuildPlan::from_lock_and_manifests when Lock::from_path fails with 'No such file or directory'. It is not returned directly: it is stored as new_lock_cause and normally leads to 'Creating a new Forc.lock file (Cause: lock file did not exist)'. It only becomes a hard failure when --locked was passed, in which case forc bails with 'The lock file ... needs to be updated (Cause: lock file did not exist)'.
Source
Thrown at forc-pkg/src/pkg.rs:686
// probably should not be the role of the `BuildPlan` constructor - instead, we should return
// the manifest alongside some lock diff type that can be used to optionally write the updated
// lock file and print the diff.
pub fn from_lock_and_manifests(
lock_path: &Path,
manifests: &MemberManifestFiles,
locked: bool,
offline: bool,
ipfs_node: &IPFSNode,
) -> Result<Self> {
// Check toolchain version
validate_version(manifests)?;
// Keep track of the cause for the new lock file if it turns out we need one.
let mut new_lock_cause = None;
// First, attempt to load the lock.
let lock = Lock::from_path(lock_path).unwrap_or_else(|e| {
new_lock_cause = if e.to_string().contains("No such file or directory") {
Some(anyhow!("lock file did not exist"))
} else {
Some(e)
};
Lock::default()
});
// Next, construct the package graph from the lock.
let mut graph = lock.to_graph().unwrap_or_else(|e| {
new_lock_cause = Some(anyhow!("Invalid lock: {}", e));
Graph::default()
});
// Since the lock file was last created there are many ways in which it might have been
// invalidated. E.g. a package's manifest `[dependencies]` table might have changed, a user
// might have edited the `Forc.lock` file when they shouldn't have, a path dependency no
// longer exists at its specified location, etc. We must first remove all invalid nodes
// before we can determine what we need to fetch.
let invalid_deps = validate_graph(&graph, manifests)?;View on GitHub (pinned to 47e5e902fa)
Solutions
- Build once without --locked to generate Forc.lock, then commit it to version control.
- If you intentionally do not track the lock, remove --locked from the command/CI job.
- Check .gitignore does not exclude Forc.lock when reproducibility is required.
Example fix
# before (fails when Forc.lock is absent) forc build --locked # after git add Forc.lock && git commit -m "chore: track Forc.lock" forc build --locked
Defensive patterns
Strategy: validation
Validate before calling
let lock = std::path::Path::new("Forc.lock");
if !lock.exists() {
// generate it before any --locked run:
// forc build && git add Forc.lock && git commit
} Prevention
- Commit Forc.lock to version control for applications and contracts.
- Only pass --locked in CI after verifying the lock is present in the repo.
- Do not gitignore Forc.lock if you need reproducible builds.
When it happens
Trigger: First build of a project (no Forc.lock yet); Forc.lock deleted by forc clean or by hand; Forc.lock gitignored in a fresh clone; any of these combined with the locked flag (e.g. 'forc build --locked' or locked fetches in CI).
Common situations: CI pipelines that use --locked to enforce reproducibility on a repo whose Forc.lock was never committed; templates that gitignore Forc.lock; fresh clones by new contributors.
Related errors
- Invalid lock: {}
- lock file did not match manifest
- failed to serialize lock file: {}
- unable to find the user home directory
- failed to read {}: {}
AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16).
Data as JSON: /api/errors/608e888fd614a420.
Report an issue: GitHub.