windmill-labs/windmill · critical
could not create initial server dir
Error message
could not create initial server dir
What it means
At server startup, windmill_main creates the base WINDMILL_DIR directory (usually /tmp/windmill) recursively with tokio's DirBuilder and .expect()s success. If creation fails, the process panics with this message — the server cannot run without its base directory for job files, caches, and storage.
Source
Thrown at backend/src/main.rs:1232
send_logs_to_object_store(&conn, &hostname, &mode);
#[cfg(all(not(target_env = "msvc"), feature = "jemalloc"))]
if !worker_mode {
monitor_mem().await;
}
let addr = SocketAddr::from((server_bind_address, port));
let listener = tokio::net::TcpListener::bind(addr)
.await
.context("binding main windmill server")?;
let (base_internal_tx, base_internal_rx) = tokio::sync::oneshot::channel::<String>();
DirBuilder::new()
.recursive(true)
.create(&*WINDMILL_DIR)
.expect("could not create initial server dir");
#[cfg(feature = "tantivy")]
let should_index_jobs = mode == Mode::Indexer || mode_and_addons.indexer;
#[cfg(feature = "tantivy")]
if should_index_jobs {
if let Some(db) = conn.as_sql() {
reload_indexer_config(&db).await;
}
}
#[cfg(feature = "tantivy")]
let (index_reader, index_writer) = if should_index_jobs {
if let Some(db) = conn.as_sql() {
let mut indexer_rx = killpill_rx.resubscribe();
let (mut reader, mut writer) = (None, None);
tokio::select! {View on GitHub (pinned to e474e8803c)
Solutions
- Check the panic's underlying io error in logs; verify the parent of WINDMILL_DIR (default /tmp/windmill) is writable by the server user: `ls -ld /tmp /tmp/windmill`.
- Remove or rename any non-directory file occupying the path.
- Point WINDMILL_PATH env at a writable location (e.g. a persistent volume mount) if /tmp is read-only.
- Fix container/security-manager settings (drop read-only rootfs/ProtectTmp restrictions) or run as a user with write access.
Example fix
// before (panic on failure)
DirBuilder::new().recursive(true).create(&*WINDMILL_DIR)
.expect("could not create initial server dir");
// after (fail with context instead of bare panic)
DirBuilder::new().recursive(true).create(&*WINDMILL_DIR)
.await
.unwrap_or_else(|e| panic!("could not create initial server dir {}: {e}", *WINDMILL_DIR)); Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: verify the base dir can be created before starting the server
let dir = std::path::Path::new(&*WINDMILL_DIR);
if let Some(parent) = dir.parent() {
let md = std::fs::metadata(parent)?;
if md.permissions().readonly() {
return Err(format!("{} is not writable; set WINDMILL_PATH to a writable location", parent.display()));
}
} Try / catch
// Startup panics via expect; wrap pre-checks in your launcher/container entrypoint:
match std::fs::create_dir_all(&*WINDMILL_DIR) {
Ok(_) => {},
Err(e) => {
eprintln!("could not create initial server dir {}: {e}", *WINDMILL_DIR);
std::process::exit(1);
}
} Prevention
- Ensure the server user can write to WINDMILL_DIR's parent (default /tmp)
- Avoid read-only root filesystems or ProtectTmp hardening without a writable volume
- Set WINDMILL_PATH to a dedicated writable persistent volume in containers
- Pre-create the directory in the container image/entrypoint with correct ownership
When it happens
Trigger: Starting the windmill server binary where creating WINDMILL_DIR fails: the parent path is not writable by the server user, a non-directory file already occupies the path, read-only root filesystem, or restrictive container volume permissions.
Common situations: Docker/Kubernetes containers running as non-root with read-only or unwritable /tmp; systemd service with a hardened ProtectTmp/ReadOnlyPaths; WINDMILL_PATH/WINDMILL_DIR env pointing into a mounted file or missing volume.
Related errors
- could not create dir '{directory_path}': {e}
- Failed to set permissions to {}: {e}
- Could not generate tsconfig: ${error instanceof Error ? erro
- Error reading dir: ${localP}, ${e}
- File not found: ${filePath}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f0cc5a216c75e64f.
Report an issue: GitHub.