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
- Delete Forc.lock and rebuild without --locked to regenerate it, then commit.
- Prefer 'forc update' or editing Forc.toml dependencies over hand-editing the lock.
- 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
- Never hand-edit Forc.lock; change dependencies in Forc.toml and regenerate.
- Resolve git merge conflicts on Forc.lock by regenerating, not by merging text.
- Pin the forc version across the team (fuel-toolchain.toml) to keep the lock schema stable.
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
- lock file did not exist
- failed to serialize lock file: {}
- failed to read {}: {}
- invalid 'source' entry for package {} lock: {:?}
- failed to parse dependency "{}": {}
AI-assisted analysis of FuelLabs/sway@47e5e902fa (2026-08-16).
Data as JSON: /api/errors/3d08f885d1bbe06f.
Report an issue: GitHub.