{"record":{"id":"0b40f8de4aa96c50","repo":"facebook/flow","slug":"failed-to-write-flowlib-file","errorCode":null,"errorMessage":"failed to write flowlib file","messagePattern":"failed to write flowlib file","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_flowlib/src/lib.rs","lineNumber":104,"sourceCode":"pub fn path_of_libdir(libdir: &LibDir) -> &Path {\n    match libdir {\n        LibDir::Prelude(path) => path,\n        LibDir::Flowlib(path) => path,\n        LibDir::Tslib(path) => path,\n    }\n}\n\nfn mkdir(libdir: &LibDir) {\n    let path = path_of_libdir(libdir);\n    let parent_dir = path.parent().expect(\"libdir path should have a parent\");\n    sys_utils::mkdir_no_fail(parent_dir)\n        .unwrap_or_else(|e| panic!(\"mkdir_no_fail({:?}): {}\", parent_dir, e));\n    sys_utils::mkdir_no_fail(path).unwrap_or_else(|e| panic!(\"mkdir_no_fail({:?}): {}\", path, e));\n}\n\nfn write_flowlib(dir: &Path, (filename, contents): &(&str, &str)) {\n    let file = dir.join(filename);\n    fs::write(&file, contents).expect(\"failed to write flowlib file\");\n}\n\npub fn extract(libdir: &LibDir) {\n    mkdir(libdir);\n    let (path, lib) = match libdir {\n        LibDir::Prelude(path) => (path.as_path(), BuiltinLib::Prelude),\n        LibDir::Flowlib(path) => (path.as_path(), BuiltinLib::Flowlib),\n        LibDir::Tslib(path) => (path.as_path(), BuiltinLib::Tslib),\n    };\n    for entry in contents(lib) {\n        write_flowlib(path, entry);\n    }\n}\n\npub fn extract_if_missing(libdir: &LibDir) {\n    let sentinel_name = match libdir {\n        LibDir::Flowlib(_) => \"core.js\",\n        LibDir::Prelude(_) => \"prelude.js\",","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_flowlib/src/lib.rs#L86-L122","documentation":"Panics when fs::write fails while extract() materializes the embedded flowlib/prelude/tslib files into the lib dir. mkdir created the directories just before, so failure means permissions, a read-only filesystem, concurrent removal of the dir, or a full disk at write time.","triggerScenarios":"Running extract (or extract_if_missing) when the lib dir or its parent is owned by another user (e.g. created by a previous sudo run); the dir is on a read-only container layer; two flow processes extract into the same dir and one wipes it mid-write; disk full.","commonSituations":"Stale flowlib directory owned by root after running flow with sudo; Docker/Kubernetes read-only root filesystems without a writable overlay for the lib dir; Windows antivirus briefly locking freshly written files; shared CI caches with mixed UIDs.","solutions":["Remove the stale lib dir (the whole flowlib temp path) and let extract recreate it with current user ownership","Check ownership/permissions on the lib dir path and its parent; chmod/chown as needed","Point the lib dir at a writable location (temp dir override / TMPDIR) when on a read-only filesystem","Ensure only one process extracts into a given lib dir at a time (extract_if_missing guards this)"],"exampleFix":"// before\nfn write_flowlib(dir: &Path, (filename, contents): &(&str, &str)) {\n    let file = dir.join(filename);\n    fs::write(&file, contents).expect(\"failed to write flowlib file\");\n}\n\n// after — one clean retry after wiping a stale/locked dir\nfn write_flowlib(dir: &Path, (filename, contents): &(&str, &str)) {\n    let file = dir.join(filename);\n    if let Err(e) = fs::write(&file, contents) {\n        let _ = fs::remove_dir_all(dir);\n        sys_utils::mkdir_no_fail(dir).unwrap_or_else(|e| panic!(\"mkdir_no_fail({dir:?}): {e}\"));\n        fs::write(&file, contents).unwrap_or_else(|e| panic!(\"failed to write flowlib file after retry: {e}\"));\n    }\n}","handlingStrategy":"retry","validationCode":"// Pre-check that the lib dir is writable before extract()\nfn dir_writable(dir: &Path) -> bool {\n    let probe = dir.join(\".write_probe\");\n    let ok = std::fs::write(&probe, b\"\").is_ok();\n    let _ = std::fs::remove_file(&probe);\n    ok\n}\n\nif !dir_writable(libdir_path) {\n    return Err(anyhow::anyhow!(\"libdir {:?} not writable\", libdir_path));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never run flow as root and then as a normal user against the same lib dir (ownership mismatch)","Prefer extract_if_missing so extraction is attempted once, not per run","Give containers a writable temp/lib location (TMPDIR) on read-only filesystems","Wipe and re-extract the lib dir after permission or ownership changes"],"tags":["rust","filesystem","permissions","disk-full","flowlib"],"backgroundTag":"permission-denied-write","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}