windmill-labs/windmill · error
Couldn't write text file at {}: {}
Error message
Couldn't write text file at {}: {} What it means
Windmill's Ansible worker creates file resources inside the job directory before running the playbook. When write_file_at_user_defined_location cannot write the text content at the user-specified target path, the worker wraps the underlying IO error in this message. It aborts the job's file-resource setup so the playbook never runs with missing files.
Source
Thrown at backend/windmill-worker/src/ansible_executor.rs:2295
)
.map_err(|e| anyhow!("Couldn't write inventory: {}", e))?;
nsjail_mounts.push(
define_nsjail_mount(job_dir, &validated_path)
.map_err(|e| anyhow!("Inventory path (a.k.a. `name`) is invalid: {}", e))?,
);
logs.push_str(&format!("\nCreated inventory `{}`", inventory.name));
}
for file_res in &r.file_resources {
let r =
get_resource_or_variable_content(client, &file_res.resource_path, job_id.to_string())
.await?;
let path = file_res.target_path.clone();
let validated_path =
write_file_at_user_defined_location(job_dir, path.as_str(), &r, file_res.mode)
.map_err(|e| anyhow!("Couldn't write text file at {}: {}", path, e))?;
nsjail_mounts.push(
define_nsjail_mount(job_dir, &validated_path)
.map_err(|e| anyhow!("File resource path is invalid: {}", e))?,
);
logs.push_str(&format!(
"\nCreated {} from {:?}",
file_res.target_path, file_res.resource_path
));
}
append_logs(job_id, w_id, logs, conn).await;
Ok(nsjail_mounts)
}
async fn get_resource_or_variable_content(
client: &AuthedClient,View on GitHub (pinned to e474e8803c)
Solutions
- Fix the file resource's target_path to be a relative path inside the job directory
- Check the underlying OS error appended to the message (permissions, ENOSPC, EISDIR) and correct the target
- Verify the resource content resolves (the preceding get_resource_or_variable_content succeeded) and that the file resource 'mode' is a valid octal mode like '644'
- If the worker filesystem is full, free space or move the worker's job dirs to larger storage
Example fix
// before
{"target_path": "../../../etc/evil.txt", "resource_path": "u/admin/notes"}
// after
{"target_path": "files/notes.txt", "resource_path": "u/admin/notes"} Defensive patterns
Strategy: validation
Validate before calling
const p = fileRes.target_path;
if (!p || p.includes('..') || path.isAbsolute(p)) {
throw new Error(`target_path must be a relative path inside the job dir: ${p}`);
} Type guard
function isSafeRelativePath(p: string): boolean {
return p.length > 0 && !path.isAbsolute(p) && !p.split('/').includes('..');
} Prevention
- Keep target_path relative and free of '..' segments
- Validate file resource modes are octal strings
- Monitor worker disk usage
When it happens
Trigger: A script/flow job with file resources whose target_path points outside the allowed job directory, is a directory rather than a file, contains invalid characters, or whose mode string is malformed; also when the job_dir filesystem is full or read-only.
Common situations: Users set a target_path with '..' segments or an absolute path escaping the job dir; the target path collides with an existing directory; disk quota exceeded on the worker node.
Related errors
- Couldn't write inventory: {}
- File resource path is invalid: {}
- Directory '{}' already exists and is not empty
- File not found: ${filePath}
- Cannot push flow ${remotePath}: step(s) reference non-worksp
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/91357972b7c43654.
Report an issue: GitHub.