{"record":{"id":"87ca97f2c107384a","repo":"windmill-labs/windmill","slug":"invalid-file-resource-should-be-a-dictionary","errorCode":null,"errorMessage":"Invalid file resource: Should be a dictionary.","messagePattern":"Invalid file resource: Should be a dictionary\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/parsers/windmill-parser-yaml/src/lib.rs","lineNumber":843,"sourceCode":"        if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String(\"resource\".to_string())) {\n            return Ok(FileResource {\n                resource_path: ResourceOrVariablePath::Resource(resource_path.clone()),\n                target_path,\n                mode,\n            });\n        }\n        if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String(\"variable\".to_string())) {\n            return Ok(FileResource {\n                resource_path: ResourceOrVariablePath::Variable(resource_path.clone()),\n                target_path,\n                mode,\n            });\n        }\n        return Err(anyhow!(\n            \"Files should have a `resource` or `variable` field that will be the contents of the local text file\"\n        ));\n    }\n    return Err(anyhow!(\"Invalid file resource: Should be a dictionary.\"));\n}\n\nfn yaml_to_json(yaml: &Yaml) -> serde_json::Value {\n    match yaml {\n        Yaml::Array(arr) => {\n            let json_array: Vec<serde_json::Value> = arr.into_iter().map(yaml_to_json).collect();\n            serde_json::Value::Array(json_array)\n        }\n        Yaml::Hash(hash) => {\n            let json_object = hash\n                .into_iter()\n                .map(|(k, v)| {\n                    let key = match k {\n                        Yaml::String(s) => s.clone(),\n                        _ => k.as_str().unwrap_or(\"\").to_string(),\n                    };\n                    (key, yaml_to_json(v))\n                })","sourceCodeStart":825,"sourceCodeEnd":861,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/parsers/windmill-parser-yaml/src/lib.rs#L825-L861","documentation":"parse_file_resource expects each file entry to be a YAML mapping (dictionary). This error is thrown when the parsed Yaml node is anything other than a Yaml::Hash — a string, number, list, or null — so no fields like `target`, `resource` or `variable` can even be read.","triggerScenarios":"A `files:` section whose entries are bare strings or a list of lists, e.g. `files: [/etc/app.conf]` or `files: - target` written as a plain scalar; also `files:` with a null/empty entry reaching the parser.","commonSituations":"Converting from a plain list-of-paths format that Windmill doesn't accept; YAML indentation errors that flatten a mapping into a scalar; passing a JSON array of strings instead of array of objects; empty list items left after editing.","solutions":["Write each file entry as a mapping with `- target: ...` plus `resource:` or `variable:` keys.","Fix indentation so each entry is a dictionary, not a bare string.","Remove empty (`null`) entries from the files list.","Validate the YAML with a linter (yamllint) before deploying to catch structural flattening."],"exampleFix":"// before\nfiles:\n  - /etc/app.conf\n// after\nfiles:\n  - target: /etc/app.conf\n    resource: u/admin/app_config","handlingStrategy":"type-guard","validationCode":"fn validate_files_shape(files: &serde_yaml::Value) -> Result<(), String> {\n    let list = files.as_sequence().ok_or(\"files must be a list\")?;\n    for (i, e) in list.iter().enumerate() {\n        if e.as_mapping().is_none() {\n            return Err(format!(\"files[{i}] must be a mapping with target/resource fields\"));\n        }\n    }\n    Ok(())\n}","typeGuard":"fn is_file_entry(v: &serde_yaml::Value) -> bool {\n    v.as_mapping().map(|m| m.contains_key(\"target\")).unwrap_or(false)\n}","tryCatchPattern":"match deploy(yaml) {\n    Err(e) if e.to_string().contains(\"Should be a dictionary\") => {\n        eprintln!(\"Write file entries as mappings: - target: ... / resource: ...\\n{e}\");\n    }\n    other => other,\n}","preventionTips":["Write entries as mappings: `- target: /path` with nested keys, never bare strings","Check indentation — a mis-indented block can flatten a mapping into a scalar","Remove null/empty items from lists","Lint YAML structure before deploy"],"tags":["yaml","structure","file-resource","ansible"],"backgroundTag":"invalid-yaml-structure","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}