vectordotdev/vector · error

UNSUPPORTED_YAML_MERGE_KEY

Error message

UNSUPPORTED_YAML_MERGE_KEY

What it means

When parsing a YAML feature config, load_and_extract scans the deserialized serde_yaml::Value for merge keys (`<<:` or `<<-`). serde_yaml does not resolve YAML merge keys into the target struct, so configs relying on them would silently lose fields; the tool proactively bails with the UNSUPPORTED_YAML_MERGE_KEY message rather than produce wrong feature lists.

Solutions

  1. Remove the merge key and inline the merged fields explicitly
  2. Resolve the anchors manually: replace `<<: *base` with the full copied key/value pairs
  3. Rewrite the file in TOML or JSON, which have no merge-key semantics

Example fix

// before
sinks:
  my_sink:
    <<: *common
    type: console
// after
sinks:
  my_sink:
    type: console
    inputs: ["*"]
    encoding: json
Defensive patterns

Strategy: validation

Validate before calling

fn uses_merge_key(yaml_text: &str) -> bool {
    yaml_text.lines().any(|l| l.trim_start().starts_with("<<:"))
}
if uses_merge_key(&text) { panic!("resolve YAML merge keys before processing"); }

Prevention

When it happens

Trigger: Calling load_and_extract on a .yaml/.yml file whose mapping (at any nesting depth) contains a `<<:` merge key, typically used with YAML anchors to share component options.

Common situations: Copying a Kubernetes-style YAML config that uses anchors-and-merge-keys DRY patterns into a Vector feature config; refactoring shared sink settings with `<<: *defaults`.

Related errors


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

Appendix: source

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

}

pub fn load_and_extract(filename: &Path) -> Result<Vec<String>> {
    let config = fs::read_to_string(filename)
        .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

View on GitHub (pinned to bdb87aeaa4)