{"record":{"id":"d660376c3e7ea744","repo":"vectordotdev/vector","slug":"failed-to-get-extension-for-input-path","errorCode":null,"errorMessage":"Failed to get extension for: {input_path:?}","messagePattern":"Failed to get extension for: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/convert_config.rs","lineNumber":117,"sourceCode":"                }\n                exitcode::SOFTWARE\n            }\n        }\n    }\n}\n\nfn convert_config(\n    input_path: &Path,\n    output_path: &Path,\n    output_format: Format,\n) -> Result<(), Vec<String>> {\n    if output_path.exists() {\n        return Err(vec![format!(\"Output path {output_path:?} exists\")]);\n    }\n    let input_format = match Format::from_str(\n        input_path\n            .extension()\n            .unwrap_or_else(|| panic!(\"Failed to get extension for: {input_path:?}\"))\n            .to_str()\n            .unwrap_or_else(|| panic!(\"Failed to convert OsStr to &str for: {input_path:?}\")),\n    ) {\n        Ok(format) => format,\n        Err(_) => return Ok(()), // skip irrelevant files\n    };\n\n    if input_format == output_format {\n        return Ok(());\n    }\n\n    #[allow(clippy::print_stdout)]\n    {\n        println!(\"Converting {input_path:?} config to {output_format:?}.\");\n    }\n    let file_contents = fs::read_to_string(input_path).map_err(|e| vec![e.to_string()])?;\n    let builder: ConfigBuilder = format::deserialize(&file_contents, input_format)?;\n    let config = builder.build()?;","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/src/convert_config.rs#L99-L135","documentation":"convert_config determines the input format from the input file's extension. If the path has no extension, Option::unwrap_or_else panics with 'Failed to get extension for: <path>'. Only files whose extension maps to a known Format (yaml/json/toml) are converted; others are skipped gracefully.","triggerScenarios":"Calling convert_config with an input path lacking an extension (e.g. 'config' instead of 'config.yaml'), or a path ending in a dot or a hidden dotfile like '.yaml' whose extension() is Some but unusual — the panic case is strictly extension() == None.","commonSituations":"Config files named without extensions (e.g. 'vector'), paths that are directories passed by mistake, or paths copied from URLs after stripping the extension.","solutions":["Rename the input file to include a supported extension (.yaml, .yml, .json, .toml)","Pass a copy of the file with the correct extension if the original must keep its name","Handle the case upstream: only call convert_config on paths where Path::extension().is_some()","Patch to return an Err(Vec<String>) for extension-less files instead of panicking"],"exampleFix":"// before\n.unwrap_or_else(|| panic!(\"Failed to get extension for: {input_path:?}\"))\n// after\nmatch input_path.extension() {\n    Some(ext) => ext,\n    None => return Err(vec![format!(\"Input path {input_path:?} has no extension\")]),\n}","handlingStrategy":"validation","validationCode":"fn has_known_ext(p: &std::path::Path) -> bool {\n    matches!(p.extension().and_then(|e| e.to_str()), Some(\"yaml\" | \"yml\" | \"json\" | \"toml\"))\n}","typeGuard":"fn ext_of(p: &std::path::Path) -> Option<String> { p.extension()?.to_str().map(|s| s.to_string()) }","tryCatchPattern":null,"preventionTips":["Keep config files with recognized extensions (.yaml/.yml/.json/.toml)","Skip or rename extension-less files before batch conversion","When scripting the tool, filter inputs with `find -name '*.yaml' -o -name '*.json' -o -name '*.toml'`"],"tags":["rust","panic","filesystem","path"],"backgroundTag":"invalid-argument-format","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"}