{"record":{"id":"925c7a6e3639cf34","repo":"facebook/flow","slug":"replacement-printer-input-file-couldn-t-be","errorCode":null,"errorMessage":"Replacement_printer: Input file, \"{}\", couldn't be read.","messagePattern":"Replacement_printer: Input file, \"(.+?)\", couldn't be read\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rust_port/crates/flow_parser_utils_output/src/replacement_printer.rs","lineNumber":42,"sourceCode":"    list_utils::to_string(\n        \"\",\n        |(s, e, p): &(usize, usize, String)| {\n            format!(\"Start: <{}> End: <{}> Patch: <{}>\\n\", s, e, p)\n        },\n        p,\n    )\n}\n\nfn with_content_of_file_input<T>(file: &FileInput, f: impl FnOnce(&str) -> T) -> T {\n    match file.content_of_file_input() {\n        Ok(contents) => f(&contents),\n        Err(_) => {\n            let file_name = file.filename_of_file_input();\n            let error_msg = format!(\n                \"Replacement_printer: Input file, \\\"{}\\\", couldn't be read.\",\n                file_name\n            );\n            panic!(\"{}\", error_msg)\n        }\n    }\n}\n\npub fn mk_loc_patch_ast_differ(opts: &Opts, diff: &NodeChanges) -> LocPatch {\n    ast_diff_printer::edits_of_changes(opts, diff)\n}\n\npub fn mk_patch_ast_differ(opts: &Opts, diff: &NodeChanges, content: &str) -> Patch {\n    let offset_table = OffsetTable::make(content);\n    let offset = |pos: Position| -> usize { offset_table.offset(pos).unwrap() as usize };\n    mk_loc_patch_ast_differ(opts, diff)\n        .into_iter()\n        .map(|(loc, text)| (offset(loc.start), offset(loc.end), text))\n        .collect()\n}\n\npub fn mk_patch_ast_differ_unsafe(opts: &Opts, diff: &NodeChanges, file: &FileInput) -> Patch {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/facebook/flow/blob/f88ac94bcf6992f5d5a158854d94613ebb92c6e6/rust_port/crates/flow_parser_utils_output/src/replacement_printer.rs#L24-L60","documentation":"The replacement printer produces codemod output by reading the original file and applying an AST-diff patch to its text. with_content_of_file_input() calls content_of_file_input(); if that read returns Err — missing file, permission denied, path is a directory — the function panics with the filename, because computing replacements without the source content is impossible.","triggerScenarios":"Running a codemod/transform that routes through the replacement printer when the FileInput path no longer exists or is unreadable at print time: the file was deleted after discovery (another codemod in the same batch, a concurrent git operation), the path is wrong, or permissions deny the read.","commonSituations":"Codemods run while editors/watchers rewrite files; batched codemods where an earlier one deletes inputs of a later one; sandboxes without read access; --input arguments that are directories or have typos; files swapped by a rebase between diffing and printing.","solutions":["Verify the filename from the panic message: test -r <file>; fix the input path if it is wrong.","Re-run on a clean checkout with concurrent tooling stopped (stash, close the editor, stop watchers).","When batching codemods, run them sequentially and re-stat each input right before the printing step, skipping deleted files.","Patch with_content_of_file_input to return an error or skip-with-warning instead of panicking, if you control the fork."],"exampleFix":"// before\nwith_content_of_file_input(&file, |content| print_patches(content));\n\n// after: guard, then print\nif file.content_of_file_input().is_err() {\n    eprintln!(\"skipping unreadable input: {}\", file.filename_of_file_input());\n    return Ok(());\n}\nwith_content_of_file_input(&file, |content| print_patches(content));","handlingStrategy":"validation","validationCode":"use std::io::Read;\n\nfn file_readable(path: &str) -> bool {\n    std::fs::File::open(path)\n        .and_then(|mut f| { let mut b = [0u8; 1]; f.read(&mut b).map(|_| ()) })\n        .is_ok()\n}\n\n// skip inputs that would panic the replacement printer\nif !file_readable(input_path) { continue; }","typeGuard":null,"tryCatchPattern":"let out = std::panic::catch_unwind(|| with_content_of_file_input(&file, print_fn));\nif out.is_err() {\n    eprintln!(\"skipping unreadable input: {}\", file.filename_of_file_input());\n    continue; // codemod continues with remaining files\n}","preventionTips":["Run codemods on a clean checkout with editors, watchers, and formatters stopped.","Re-stat each input file right before printing; skip anything that vanished since discovery.","Run batched codemods sequentially so one never deletes another's input.","Resolve --input paths to absolute paths once at CLI parse time."],"tags":["codemod","file-io","replacement-printer","ast-diff","race-condition"],"backgroundTag":"file-not-found","analyzedSha":"f88ac94bcf6992f5d5a158854d94613ebb92c6e6","analyzedAt":"2026-08-20T10:41:37.992Z","contentChangedAt":"2026-08-20T10:41:37.992Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}