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

  1. Build once without --locked to generate Forc.lock, then commit it to version control.
  2. If you intentionally do not track the lock, remove --locked from the command/CI job.
  3. 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

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


AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16). Data as JSON: /api/errors/608e888fd614a420. Report an issue: GitHub.