{"record":{"id":"7e704553ba495c42","repo":"vectordotdev/vector","slug":"failed-to-read-dir-input-path","errorCode":null,"errorMessage":"Failed to read dir: {input_path:?}","messagePattern":"Failed to read dir: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/convert_config.rs","lineNumber":155,"sourceCode":"    fs::write(output_path, output_string).map_err(|e| vec![e.to_string()])?;\n\n    #[allow(clippy::print_stdout)]\n    {\n        println!(\"Wrote result to {output_path:?}.\");\n    }\n    Ok(())\n}\n\nfn walk_dir_and_convert(\n    input_path: &Path,\n    output_dir: &Path,\n    output_format: Format,\n) -> Result<(), Vec<String>> {\n    let mut errors = Vec::new();\n\n    if input_path.is_dir() {\n        for entry in fs::read_dir(input_path)\n            .unwrap_or_else(|_| panic!(\"Failed to read dir: {input_path:?}\"))\n        {\n            let entry_path = entry\n                .unwrap_or_else(|_| panic!(\"Failed to get entry for dir: {input_path:?}\"))\n                .path();\n            let new_output_dir = if entry_path.is_dir() {\n                let last_component = entry_path\n                    .file_name()\n                    .unwrap_or_else(|| panic!(\"Failed to get file_name for {entry_path:?}\"));\n                let new_dir = output_dir.join(last_component);\n\n                if !new_dir.exists() {\n                    fs::create_dir_all(&new_dir)\n                        .unwrap_or_else(|_| panic!(\"Failed to create output dir: {new_dir:?}\"));\n                }\n                new_dir\n            } else {\n                output_dir.to_path_buf()\n            };","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/convert_config.rs#L137-L173","documentation":"walk_dir_and_convert recursively converts all supported config files under a directory. It calls fs::read_dir on the input directory and, if listing fails, panics with 'Failed to read dir: <path>' rather than recording the error in its collected error list.","triggerScenarios":"Calling walk_dir_and_convert (directly or via cmd/convert_all_from_dir) on a path that was a directory at the is_dir() check but cannot be listed: permission denied, directory deleted concurrently, or it is a symlink to an unreadable location.","commonSituations":"Running the recursive converter on directories with restrictive permissions (e.g. another user's home), racing with cleanup jobs that delete directories, or broken symlinks to directories.","solutions":["Check directory readability: `ls <dir>` / verify with `test -r <dir>`","Run the tool with sufficient permissions or as the directory owner","Fix or remove broken symlinks pointing at nonexistent targets","Patch to push the io::Error into the errors Vec instead of panicking"],"exampleFix":"// before\nfs::read_dir(input_path)\n    .unwrap_or_else(|_| panic!(\"Failed to read dir: {input_path:?}\"))\n// after\nlet entries = match fs::read_dir(input_path) {\n    Ok(e) => e,\n    Err(err) => {\n        errors.push(format!(\"Failed to read dir {input_path:?}: {err}\"));\n        return Ok(());\n    }\n};","handlingStrategy":"validation","validationCode":"if !fs::metadata(dir).map(|m| m.is_dir()).unwrap_or(false) || fs::read_dir(dir).is_err() {\n    eprintln!(\"directory {:?} is not readable\", dir);\n    std::process::exit(2);\n}","typeGuard":"fn is_readable_dir(p: &std::path::Path) -> bool { fs::read_dir(p).is_ok() }","tryCatchPattern":null,"preventionTips":["Check directory readability before recursive runs","Avoid walking directories being concurrently deleted or rebuilt","Copy/snapshot trees to local disk before converting from network mounts"],"tags":["rust","panic","filesystem","directory"],"backgroundTag":"file-read-failed","analyzedSha":"bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013","analyzedAt":"2026-09-16T02:53:35.741Z","contentChangedAt":"2026-09-16T02:53:35.741Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}