windmill-labs/windmill · error

{section} dependency should be a map

Error message

{section} dependency should be a map

What it means

add_versions_to_requirements_yaml pins role/collection versions into an Ansible requirements file. update_versions first asserts the top-level parsed YAML document is a mapping. This error is thrown when the requirements YAML root is not a map — e.g. it is a list at the top level, a scalar, or an empty document — so the `roles`/`collections` sections cannot be looked up.

Source

Thrown at backend/parsers/windmill-parser-yaml/src/lib.rs:882

        }
        Yaml::String(s) => serde_json::Value::String(s.to_string()),
        Yaml::Integer(i) => serde_json::Value::Number(i.clone().into()),
        Yaml::Real(r) => serde_json::Value::Number(r.parse().unwrap_or(0.into())),
        Yaml::Boolean(b) => serde_json::Value::Bool(*b),
        Yaml::Null => serde_json::Value::Null,
        _ => serde_json::Value::Null,
    }
}

fn update_versions(
    section: &str,
    yaml: &mut Yaml,
    versions: &HashMap<String, String>,
) -> anyhow::Result<String> {
    let mut logs = String::new();

    let Yaml::Hash(ref mut m) = yaml else {
        return Err(anyhow!("{section} dependency should be a map"));
    };

    if let Some(Yaml::Array(elements)) = m.get_mut(&Yaml::String(section.to_string())) {
        for el in elements {
            let Yaml::Hash(ref mut h) = el else {
                return Err(anyhow!("{section} dependency element should be a map"));
            };

            if let Some(name) = h
                .get(&Yaml::String("name".to_string()))
                .and_then(|n| n.as_str())
            {
                if let Some(version) = versions.get(name) {
                    h.insert(
                        Yaml::String("version".to_string()),
                        Yaml::String(version.to_string()),
                    );
                } else {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Restructure the requirements file as a map with `roles:` and `collections:` keys, each holding a list of {name, version} entries.
  2. If the file is empty, add at least `roles: []` / `collections: []`.
  3. Convert legacy top-level-list requirements to the modern map format supported by ansible-galaxy 2.10+.
  4. Validate the parsed root is a mapping before calling the API.

Example fix

# before (legacy top-level list)
- src: geerlingguy.docker
# after
roles:
  - name: geerlingguy.docker
    version: 6.1.0
Defensive patterns

Strategy: type-guard

Validate before calling

fn validate_requirements_root(input: &str) -> Result<(), String> {
    let doc: serde_yaml::Value = serde_yaml::from_str(input).map_err(|e| e.to_string())?;
    if doc.as_mapping().is_none() {
        return Err("requirements.yml root must be a mapping with roles:/collections: keys".into());
    }
    Ok(())
}

Type guard

fn is_requirements_map(v: &serde_yaml::Value) -> bool {
    v.as_mapping().map(|m| m.contains_key("roles") || m.contains_key("collections")).unwrap_or(false)
}

Try / catch

match pin_versions(input, &roles, &collections) {
    Err(e) if e.to_string().contains("dependency should be a map") => {
        eprintln!("requirements.yml root must be a map: roles:\n  - name: ...\n{e}");
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling add_versions_to_requirements_yaml with input whose first YAML document is `[]`, a plain string, or empty; legacy requirements files that are a top-level list (`- src: ...`) rather than `roles:`/`collections:` maps.

Common situations: Old-style ansible-galaxy requirements.yml (pre-2.10) with a top-level sequence of roles; an empty requirements file created by scaffolding; a YAML parse producing a scalar due to bad indentation.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/d03ed86af5605d99. Report an issue: GitHub.