{"record":{"id":"2adcaeafd273f651","repo":"FuelLabs/sway","slug":"missing-pkg-string","errorCode":null,"errorMessage":"missing pkg string","messagePattern":"missing pkg string","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"forc-pkg/src/lock.rs","lineNumber":326,"sourceCode":"        false => (None, s),\n        true => {\n            // If we have the open bracket, grab everything until the closing bracket.\n            let s = &s[\"(\".len()..];\n            let mut iter = s.split(')');\n            let dep_name = iter\n                .next()\n                .ok_or_else(|| anyhow!(\"missing closing parenthesis\"))?;\n            // The rest is the unique package string and possibly the salt.\n            let s = &s[dep_name.len() + \")\".len()..];\n            (Some(dep_name), s)\n        }\n    };\n\n    // Check for salt.\n    let mut iter = s.split('(');\n    let pkg_str = iter\n        .next()\n        .ok_or_else(|| anyhow!(\"missing pkg string\"))?\n        .trim();\n    let salt_str = iter.next().map(|s| s.trim()).map(|s| &s[..s.len() - 1]);\n    let salt = match salt_str {\n        Some(salt_str) => Some(\n            fuel_tx::Salt::from_str(salt_str)\n                .map_err(|e| anyhow!(\"invalid salt in lock file: {e}\"))?,\n        ),\n        None => None,\n    };\n\n    Ok((dep_name, pkg_str, salt))\n}\n\npub fn print_diff(member_names: &HashSet<String>, diff: &Diff) {\n    print_removed_pkgs(member_names, diff.removed.iter().copied());\n    print_added_pkgs(member_names, diff.added.iter().copied());\n}\n","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/forc-pkg/src/lock.rs#L308-L344","documentation":"Intended guard in parse_pkg_dep_line for a dependency line whose package-string part is empty - a line that carries a name (optionally parenthesized) but no '<name> <source>' payload after it. Like the sibling ')' check, split-based iteration makes this branch effectively unreachable; a genuinely empty package string instead surfaces downstream as the invalid-source parse error. Encountering it means a severely mangled dependency line.","triggerScenarios":"A Forc.lock dependency line reduced to a bare name or '(name)' with everything after it missing.","commonSituations":"Truncated files; aggressive hand-editing; merge leftovers leaving only a fragment of a line.","solutions":["Restore the full 'name source' (or '(name source) salt') line, or delete Forc.lock and regenerate it with forc build.","Audit the file for truncation (check the last lines of each package block)."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Rust, reject dependency lines with an empty package-string part:\nfn has_pkg_string(line: &str) -> bool {\n    let s = line.trim().trim_start_matches('(').split(')').last().unwrap_or(\"\");\n    s.split('(').next().map(|p| !p.trim().is_empty()).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"// Practically unreachable branch; its trigger implies a mangled lock - regenerate:\nmatch parse_pkg_dep_line(line) { Err(_) => { /* rm Forc.lock; forc build */ }, Ok(v) => v }","preventionTips":["Do not truncate Forc.lock files; check file tail after suspicious writes.","Regenerate rather than repair partial lock content.","Version-control Forc.lock so damaged states are recoverable via git."],"tags":["forc","forc-pkg","lockfile","parsing","defensive-code"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}