FuelLabs/sway · warning

Invalid lock: {}

Error message

Invalid lock: {}

What it means

Recorded when the Forc.lock file could be found but lock.to_graph() failed; the {} is the graph-construction error (malformed package entries, unresolvable references, bad pinned sources). Like other lock causes, forc recovers by discarding the graph and regenerating the lock - fatal only under --locked.

Source

Thrown at forc-pkg/src/pkg.rs:695

    ) -> 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)?;
        let members: HashSet<String> = manifests.keys().cloned().collect();
        remove_deps(&mut graph, &members, &invalid_deps);

        // We know that the remaining nodes have valid paths, otherwise they would have been
        // removed. We can safely produce an initial `manifest_map`.
        let mut manifest_map = graph_to_manifest_map(manifests, &graph)?;

        // Attempt to fetch the remainder of the graph.
        let _added = fetch_graph(manifests, offline, ipfs_node, &mut graph, &mut manifest_map)?;

View on GitHub (pinned to 47e5e902fa)

Solutions

  1. Delete Forc.lock and rebuild without --locked to regenerate it, then commit.
  2. Prefer 'forc update' or editing Forc.toml dependencies over hand-editing the lock.
  3. If it persists on a freshly generated lock, check for forc version mismatch between contributors (pinned toolchain in fuel-toolchain.toml).

Example fix

# before
forc build --locked   # Invalid lock: ...

# after
rm Forc.lock
forc build && git add Forc.lock && git commit -m "chore: regenerate Forc.lock"
forc build --locked
Defensive patterns

Strategy: fallback

Validate before calling

// pre-verify the lock can round-trip into a graph
use forc_pkg::lock::Lock;
if Lock::from_path(lock_path.as_ref()).and_then(|l| l.to_graph()).is_err() {
    // lock is unusable: plan to regenerate instead of failing the build
}

Try / catch

match Lock::from_path(lock_path.as_ref()).and_then(|l| l.to_graph()) {
    Ok(graph) => use_graph(graph),
    Err(_) => {
        // fall back: discard the corrupt lock exactly once and rebuild
        let _ = std::fs::remove_file(&lock_path);
        rebuild_and_regenerate_lock()?;
    }
}

Prevention

When it happens

Trigger: Hand-edited Forc.lock introducing schema violations; a lock produced by a much older/newer forc with an incompatible schema; a git merge conflict on Forc.lock resolved by keeping fragments of both sides; truncated file.

Common situations: Branch merges that conflict on Forc.lock; upgrading forc versions and reusing an old lock; manually pinning git commits by editing the lock.

Related errors


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