{"record":{"id":"e6d4611b23611f07","repo":"FuelLabs/sway","slug":"failed-to-write-lock-file","errorCode":null,"errorMessage":"failed to write lock file: {}","messagePattern":"failed to write lock file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"forc-pkg/src/pkg.rs","lineNumber":753,"sourceCode":"                    \"The lock file {} needs to be updated (Cause: {}) \\\n                    but --locked was passed to prevent this.\",\n                    lock_path.to_string_lossy(),\n                    cause,\n                );\n            }\n            println_action_green(\n                \"Creating\",\n                &format!(\"a new `Forc.lock` file. (Cause: {cause})\"),\n            );\n            let member_names = manifests\n                .values()\n                .map(|manifest| manifest.project.name.to_string())\n                .collect();\n            crate::lock::print_diff(&member_names, &lock_diff);\n            let string = toml::ser::to_string_pretty(&new_lock)\n                .map_err(|e| anyhow!(\"failed to serialize lock file: {}\", e))?;\n            fs::write(lock_path, string)\n                .map_err(|e| anyhow!(\"failed to write lock file: {}\", e))?;\n            debug!(\"   Created new lock file at {}\", lock_path.display());\n        }\n\n        Ok(plan)\n    }\n\n    /// Produce an iterator yielding all contract dependencies of given node in the order of\n    /// compilation.\n    pub fn contract_dependencies(&self, node: NodeIx) -> impl Iterator<Item = NodeIx> + '_ {\n        let graph = self.graph();\n        let connected: HashSet<_> = Dfs::new(graph, node).iter(graph).collect();\n        self.compilation_order()\n            .iter()\n            .cloned()\n            .filter(move |&n| n != node)\n            .filter(|&n| {\n                graph\n                    .edges_directed(n, Direction::Incoming)","sourceCodeStart":735,"sourceCodeEnd":771,"githubUrl":"https://github.com/FuelLabs/sway/blob/47e5e902faa42baf652dd6a0c88cd23390c1a614/forc-pkg/src/pkg.rs#L735-L771","documentation":"The new Forc.lock serialized fine but fs::write(lock_path, string) failed; {} is the io::Error. The lock could not be persisted to disk: permission denied on the directory, read-only filesystem/mount, disk full, or lock_path colliding with a directory.","triggerScenarios":"Building in a directory the process cannot write (root-owned, chmod 555); Docker/CI read-only volume; ENOSPC; a stray directory named Forc.lock.","commonSituations":"Running forc via sudo-created project dirs; CI sandbox with read-only source mounts; full disks or quotas on build agents.","solutions":["Check write permission on the project directory (chmod u+w / chown) and that Forc.lock is a file, not a directory.","Free disk space or raise the quota if the io error is No space left on device.","Mount the workspace read-write in CI/Docker, or pre-generate the lock in a writable step."],"exampleFix":"# before: read-only mount in CI\n# - run: forc build\n#   volumeMounts: readOnly: true\n\n# after: write the lock in a writable stage\n- run: forc build\ndocker run -v $PWD:/src -w /src ghcr.io/fuellabs/forc:latest forc build","handlingStrategy":"validation","validationCode":"fn dir_is_writable(dir: &std::path::Path) -> bool {\n    let probe = dir.join(\".forc_write_probe\");\n    std::fs::write(&probe, b\"\").is_ok() && std::fs::remove_file(&probe).is_ok()\n}\n// check the project dir before building so the lock can be persisted","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run builds from directories your user can write to.","Mount CI workspaces read-write, or generate the lock in a writable stage.","Watch disk space on build agents; Forc.lock writes fail on ENOSPC."],"tags":["filesystem","io","lock-file","permissions"],"backgroundTag":null,"analyzedSha":"47e5e902faa42baf652dd6a0c88cd23390c1a614","analyzedAt":"2026-08-16T07:57:45.555Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}