dbt-labs/dbt-core · error · minijinja::Error (InvalidOperation)
Failed to write to {}: {}
Error message
Failed to write to {}: {} What it means
This error is thrown by the `write_file` helper in the run-node context when `fs::write` fails to persist a rendered payload to disk at the resolved `full_path`. It wraps the underlying OS error so the developer sees both the target path and the I/O reason. The library throws it because writing the compiled/intermediate file is a required side effect of the node context phase and cannot be silently skipped.
Source
Thrown at crates/dbt-jinja-utils/src/phases/run/run_node_context.rs:781
}
// A stale directory sitting where we now write a flat file fails with EISDIR.
if full_path.is_dir()
&& let Err(e) = fs::remove_dir_all(full_path)
{
return Err(Error::new(
ErrorKind::InvalidOperation,
format!(
"Failed to remove stale directory {}: {}",
full_path.display(),
e
),
));
}
match fs::write(full_path, payload) {
Ok(_) => Ok(()),
Err(e) => Err(Error::new(
ErrorKind::InvalidOperation,
format!("Failed to write to {}: {}", full_path.display(), e),
)),
}
}
/// Returns the function used for the submit_python_job context.
fn submit_python_job_context_fn()
-> impl Fn(&State, &[MinijinjaValue]) -> Result<MinijinjaValue, Error> + Copy {
|state: &State, args: &[MinijinjaValue]| {
// Parse arguments: submit_python_job(parsed_model, compiled_code)
if args.len() != 2 {
return Err(Error::new(
ErrorKind::InvalidOperation,
format!("submit_python_job expects 2 arguments, got {}", args.len()),
));
}
let parsed_model = &args[0];View on GitHub (pinned to 0267ce9170)
Solutions
- Inspect the wrapped OS error (`e`) in the message to identify the exact I/O cause (NotFound, PermissionDenied, AlreadyExists, etc.).
- Ensure the parent directory of the target path exists and is writable; remove any directory sitting exactly at the target path.
- Check free disk space and that the filesystem is mounted read-write.
- Re-run with correct file permissions (chown/chmod) for the user executing dbt.
Example fix
// before (stale directory blocks file write) // target/compiled.sql is a directory -> fs::write fails // after // rm -rf target/compiled.sql (or let write_file_replaces_stale_directory_at_target remove it), then re-run
Defensive patterns
Strategy: try-catch
Validate before calling
use std::path::Path;
fn ensure_writable_target(path: &Path) -> Result<(), String> {
if let Some(parent) = path.parent() {
if !parent.exists() {
std::fs::create_dir_all(parent).map_err(|e| e.to_string())?;
}
}
if path.is_dir() {
return Err(format!("{} is a directory, not a file", path.display()));
}
Ok(())
} Try / catch
match write_file(full_path, payload) {
Err(e) if e.to_string().contains("Failed to write to") => {
// inspect wrapped OS error, fix path/permissions, optionally retry
eprintln!("artifact write failed: {e}");
}
Err(e) => return Err(e),
Ok(_) => {}
} Prevention
- Always create parent directories before writing artifacts.
- Clean stale target/ directories between runs.
- Check disk space and mount flags in CI containers.
- Run dbt as a user with write access to the project directory.
When it happens
Trigger: Calling `write_file` (directly or via `write_file_creates_nested_path`, `write_file_replaces_stale_flat_file_on_parent_chain`, `write_file_replaces_stale_directory_at_target`, or the `call` entry point) when the target path is not writable: parent directory does not exist and could not be created, a stale directory occupies the target path, the filesystem is read-only, or permissions are insufficient.
Common situations: Running dbt in a container with a read-only or full disk; a previous run left a directory where a file is expected; write permissions on target/ or logs/ directories were tightened; concurrent runs racing on the same artifact path.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to write file: {e}
- Failed to create temp file
- Valid UTF-8 path
- File name can't be empty
- Schema not found for canonical FQN: {}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/36be6898b8382082.
Report an issue: GitHub.