{"record":{"id":"565814967d2f02a7","repo":"FuelLabs/sway","slug":"invalid-source-entry-for-package-lock","errorCode":null,"errorMessage":"invalid 'source' entry for package {} lock: {:?}","messagePattern":"invalid 'source' entry for package (.+?) lock: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"forc-pkg/src/lock.rs","lineNumber":191,"sourceCode":"\n    /// Given a `Lock` loaded from a `Forc.lock` file, produce the graph of pinned dependencies.\n    pub fn to_graph(&self) -> Result<pkg::Graph> {\n        let mut graph = pkg::Graph::new();\n\n        // Track the names which need to be disambiguated in the dependency list.\n        let names = self.package.iter().map(|pkg| &pkg.name[..]);\n        let disambiguate: HashSet<_> = names_requiring_disambiguation(names).collect();\n\n        // Add all nodes to the graph.\n        // Keep track of \"<name> <source>\" to node-index mappings for the edge collection pass.\n        let mut pkg_to_node: HashMap<String, pkg::NodeIx> = HashMap::new();\n        for pkg in &self.package {\n            // Note: `key` may be either `<name> <source>` or just `<name>` if disambiguation not\n            // required.\n            let key = pkg.name_disambiguated(&disambiguate).into_owned();\n            let name = pkg.name.clone();\n            let source: source::Pinned = pkg.source.parse().map_err(|e| {\n                anyhow!(\"invalid 'source' entry for package {} lock: {:?}\", name, e)\n            })?;\n            let pkg = pkg::Pinned { name, source };\n            let node = graph.add_node(pkg);\n            pkg_to_node.insert(key, node);\n        }\n\n        // On the second pass, add all edges.\n        for pkg in &self.package {\n            let key = pkg.name_disambiguated(&disambiguate);\n            let node = pkg_to_node[&key[..]];\n            // If `pkg.contract_dependencies` is None, we will be collecting an empty list of\n            // contract_deps so that we will omit them during edge adding phase\n            let contract_deps = pkg\n                .contract_dependencies\n                .as_ref()\n                .into_iter()\n                .flatten()\n                .map(|contract_dep| (contract_dep, UnparsedDepKind::Contract));","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/forc-pkg/src/lock.rs#L173-L209","documentation":"While converting a parsed Forc.lock back into a package graph (Lock::to_graph), every package entry's source string is parsed into a source::Pinned value (git+https://...#commit, path+..., registry+...). If the string matches no known pinned-source format, this error names the package and echoes the underlying parse error, pointing at that package entry in the lock.","triggerScenarios":"A Forc.lock whose [[package]] source entries are malformed: hand-edited strings, leftover merge-conflict markers, or a lock written by a different forc version whose source grammar differs from the reader's.","commonSituations":"Hand-resolved git merges of Forc.lock; upgrading/downgrading forc while keeping the old lock; scripts that rewrite locks; team members on mismatched toolchain versions.","solutions":["Delete Forc.lock and run forc build to re-resolve and regenerate it from Forc.toml - the lock is a derived artifact, never worth hand-fixing.","If the lock must be hand-maintained, correct the entry to a valid pinned form such as git+https://github.com/FuelLabs/sway?tag=v0.49.0#<40-hex-commit>.","Pin one forc version across the team and CI so lock format stays consistent."],"exampleFix":"# before (Forc.lock)\n[[package]]\nname = \"std\"\nsource = \"github.com/FuelLabs/sway\" # malformed\n\n# after\n[[package]]\nname = \"std\"\nsource = \"git+https://github.com/FuelLabs/sway?tag=v0.49.0#8b4f3dd2c6db4a1d1c0d3e0b1f0ad79d1cd4c6e4\"","handlingStrategy":"fallback","validationCode":"// Rust, validate source entries before Lock::to_graph by round-tripping:\n// let pinned: Result<source::Pinned, _> = pkg.source.parse();\n// surface the first failing package name instead of a graph-wide error.","typeGuard":null,"tryCatchPattern":"// On this error, the lock is unrecoverable-by-parsing: fall back to regeneration.\nmatch lock.to_graph() {\n    Ok(g) => { /* ... */ }\n    Err(e) => { let _ = fs::remove_file(\"Forc.lock\"); /* re-run dependency fetch */ }\n}","preventionTips":["Never hand-edit [[package]] source strings in Forc.lock.","Regenerate the lock after changing dependency sources in Forc.toml.","Pin one forc version across the team so lock grammar stays consistent.","Resolve Forc.lock merge conflicts by regenerating, not by hand-merging."],"tags":["forc","forc-pkg","lockfile","dependency-resolution"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}