windmill-labs/windmill · error
Invalid file resource: Should be a dictionary.
Error message
Invalid file resource: Should be a dictionary.
What it means
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.
Source
Thrown at backend/parsers/windmill-parser-yaml/src/lib.rs:843
if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("resource".to_string())) {
return Ok(FileResource {
resource_path: ResourceOrVariablePath::Resource(resource_path.clone()),
target_path,
mode,
});
}
if let Some(Yaml::String(resource_path)) = f.get(&Yaml::String("variable".to_string())) {
return Ok(FileResource {
resource_path: ResourceOrVariablePath::Variable(resource_path.clone()),
target_path,
mode,
});
}
return Err(anyhow!(
"Files should have a `resource` or `variable` field that will be the contents of the local text file"
));
}
return Err(anyhow!("Invalid file resource: Should be a dictionary."));
}
fn yaml_to_json(yaml: &Yaml) -> serde_json::Value {
match yaml {
Yaml::Array(arr) => {
let json_array: Vec<serde_json::Value> = arr.into_iter().map(yaml_to_json).collect();
serde_json::Value::Array(json_array)
}
Yaml::Hash(hash) => {
let json_object = hash
.into_iter()
.map(|(k, v)| {
let key = match k {
Yaml::String(s) => s.clone(),
_ => k.as_str().unwrap_or("").to_string(),
};
(key, yaml_to_json(v))
})View on GitHub (pinned to e474e8803c)
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.
Example fix
// before
files:
- /etc/app.conf
// after
files:
- target: /etc/app.conf
resource: u/admin/app_config Defensive patterns
Strategy: type-guard
Validate before calling
fn validate_files_shape(files: &serde_yaml::Value) -> Result<(), String> {
let list = files.as_sequence().ok_or("files must be a list")?;
for (i, e) in list.iter().enumerate() {
if e.as_mapping().is_none() {
return Err(format!("files[{i}] must be a mapping with target/resource fields"));
}
}
Ok(())
} Type guard
fn is_file_entry(v: &serde_yaml::Value) -> bool {
v.as_mapping().map(|m| m.contains_key("target")).unwrap_or(false)
} Try / catch
match deploy(yaml) {
Err(e) if e.to_string().contains("Should be a dictionary") => {
eprintln!("Write file entries as mappings: - target: ... / resource: ...\n{e}");
}
other => other,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid field in `mode`, expected integer like 0o644
- Files should have a `resource` or `variable` field that will
- {section} dependency should be a map
- Failed to parse yaml: {}
- Invalid inventory definition
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/87ca97f2c107384a.
Report an issue: GitHub.