{"record":{"id":"c643b4b6c6c5238a","repo":"vectordotdev/vector","slug":"invalid-filename-no-extension","errorCode":null,"errorMessage":"Invalid filename {}, no extension","messagePattern":"Invalid filename (.+?), no extension","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"vdev/src/utils/features.rs","lineNumber":121,"sourceCode":"#[derive(Deserialize)]\nstruct Component {\n    r#type: String,\n\n    #[serde(flatten)]\n    options: HashMap<String, Value>,\n}\n\npub fn load_and_extract(filename: &Path) -> Result<Vec<String>> {\n    let config = fs::read_to_string(filename)\n        .with_context(|| format!(\"failed to read {}\", filename.display()))?;\n\n    let config: FeatureConfig = match filename\n        .extension()\n        .and_then(OsStr::to_str)\n        .map(str::to_lowercase)\n        .as_deref()\n    {\n        None => bail!(\"Invalid filename {}, no extension\", filename.display()),\n        Some(\"json\") => serde_json::from_str(&config)?,\n        Some(\"toml\") => toml::from_str(&config)?,\n        Some(\"yaml\" | \"yml\") => {\n            let value: serde_yaml::Value = serde_yaml::from_str(&config)?;\n            if contains_yaml_merge_key(&value) {\n                bail!(UNSUPPORTED_YAML_MERGE_KEY);\n            }\n            serde_yaml::from_value(value)?\n        }\n        Some(_) => bail!(\"Invalid filename {}, unknown extension\", filename.display()),\n    };\n\n    let declared_features = CargoToml::load_from(&find_repo_root()?.join(\"Cargo.toml\"))?\n        .features\n        .into_keys()\n        .collect();\n\n    from_config(&config, &declared_features)","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/vectordotdev/vector/blob/bdb87aeaa4c4ff27c0ba643c1c77b21bf2ef4013/vdev/src/utils/features.rs#L103-L139","documentation":"load_and_extract reads a feature-config file and dispatches parsing on the file extension. If Path::extension() returns None (no dot in the filename, or the name ends with a dot), it cannot choose a parser and bails with this message naming the file. The tool only accepts json, toml, yaml, or yml extensions.","triggerScenarios":"Calling load_and_extract with a Path whose filename has no extension — e.g. \"config\", \"features.\", \".gitignore\"-style dotfiles whose extension parses as the whole name, or a path ending in a directory separator.","commonSituations":"Passing a temp file created without a suffix; renaming a config during refactoring and dropping the extension; globbing a directory and feeding every file (including extension-less ones) to the loader.","solutions":["Rename the file to include a supported extension: .json, .toml, .yaml, or .yml matching its actual content format","If the content is YAML but the file is named e.g. `features`, rename to `features.yaml`","Exclude extension-less files from the input set before calling load_and_extract"],"exampleFix":"// before\nlet feats = load_and_extract(Path::new(\"config/features\"))?;\n// after\nlet feats = load_and_extract(Path::new(\"config/features.yaml\"))?;","handlingStrategy":"validation","validationCode":"fn has_supported_ext(p: &Path) -> bool {\n    matches!(p.extension().and_then(|e| e.to_str()).map(|e| e.to_lowercase()).as_deref(),\n             Some(\"json\" | \"toml\" | \"yaml\" | \"yml\"))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always name config files with an explicit .yaml/.json/.toml extension","Never feed whole-directory globs blindly; filter by extension first","Preserve extensions through temp-file creation (e.g. tempfile with suffix)"],"tags":["rust","filesystem","filename","parsing"],"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"}