vectordotdev/vector · error

Invalid filename , unknown extension

Error message

Invalid filename {}, unknown extension

What it means

After picking a parser by extension, load_and_extract rejects any extension other than json, toml, yaml, or yml with this message. The tool has no deserializer registered for other formats, so files like .xml, .conf, or .cfg cannot be interpreted as a FeatureConfig.

Solutions

  1. Convert the config to one of the supported formats (YAML recommended) and use the matching extension
  2. Fix the extension typo (.tml → .toml, .yamle → .yaml)
  3. Filter the input file list to supported extensions before processing

Example fix

// before
load_and_extract(Path::new("config/features.ini"))?;
// after
load_and_extract(Path::new("config/features.toml"))?;
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED: [&str; 4] = ["json", "toml", "yaml", "yml"];
fn supported(p: &Path) -> bool {
    p.extension().and_then(|e| e.to_str()).map(|e| SUPPORTED.contains(&e.to_lowercase().as_str())).unwrap_or(false)
}

Prevention

When it happens

Trigger: Calling load_and_extract with paths like "config.xml", "features.ini", or any extension outside {json, toml, yaml, yml}.

Common situations: Pointing the feature-extraction tool at a different tool's config format; a typo such as .yamle or .tml; batch-processing a directory that mixes in unrelated file types.

Related errors


AI-assisted analysis of vectordotdev/vector@bdb87aeaa4 (2026-09-16). Data as JSON: /api/errors/5f0d611efa02fc00. Report an issue: GitHub.

Appendix: source

Thrown at vdev/src/utils/features.rs:131

        .with_context(|| format!("failed to read {}", filename.display()))?;

    let config: FeatureConfig = match filename
        .extension()
        .and_then(OsStr::to_str)
        .map(str::to_lowercase)
        .as_deref()
    {
        None => bail!("Invalid filename {}, no extension", filename.display()),
        Some("json") => serde_json::from_str(&config)?,
        Some("toml") => toml::from_str(&config)?,
        Some("yaml" | "yml") => {
            let value: serde_yaml::Value = serde_yaml::from_str(&config)?;
            if contains_yaml_merge_key(&value) {
                bail!(UNSUPPORTED_YAML_MERGE_KEY);
            }
            serde_yaml::from_value(value)?
        }
        Some(_) => bail!("Invalid filename {}, unknown extension", filename.display()),
    };

    let declared_features = CargoToml::load_from(&find_repo_root()?.join("Cargo.toml"))?
        .features
        .into_keys()
        .collect();

    from_config(&config, &declared_features)
}

fn contains_yaml_merge_key(value: &serde_yaml::Value) -> bool {
    match value {
        serde_yaml::Value::Sequence(values) => values.iter().any(contains_yaml_merge_key),
        serde_yaml::Value::Mapping(mapping) => mapping
            .iter()
            .any(|(key, value)| key.as_str() == Some("<<") || contains_yaml_merge_key(value)),
        serde_yaml::Value::Tagged(tagged) => contains_yaml_merge_key(&tagged.value),
        _ => false,

View on GitHub (pinned to bdb87aeaa4)