windmill-labs/windmill · error
WINDMILL_DIR must not end with a trailing slash, got: {dir}
Error message
WINDMILL_DIR must not end with a trailing slash, got: {dir} What it means
After resolving WINDMILL_DIR (env var or normalized temp dir), Windmill validates its shape because it later appends paths like `{dir}/windmill`, `{dir}/logs`, `{dir}/cache/`. A trailing slash would yield double slashes and break assumptions about the path format, so the process panics at initialization if WINDMILL_DIR ends with '/' or '\\'.
Source
Thrown at backend/windmill-common/src/worker.rs:834
lazy_static::lazy_static! {
pub static ref WINDMILL_DIR: String = {
let dir = std::env::var("WINDMILL_DIR")
.unwrap_or_else(|_| {
#[cfg(not(windows))]
{ "/tmp/windmill".to_string() }
#[cfg(windows)]
{
let temp = std::env::temp_dir();
let temp_str = temp.to_string_lossy();
let normalized = temp_str.trim_end_matches(&['/', '\\'][..]).replace('\\', "/");
format!("{}/windmill", normalized)
}
});
if dir.is_empty() {
panic!("WINDMILL_DIR must not be empty");
}
if dir.ends_with('/') || dir.ends_with('\\') {
panic!("WINDMILL_DIR must not end with a trailing slash, got: {dir}");
}
dir
};
pub static ref TMP_LOGS_DIR: String = format!("{}/logs", *WINDMILL_DIR);
pub static ref ROOT_CACHE_DIR: String = format!("{}/cache/", *WINDMILL_DIR);
pub static ref HUB_CACHE_DIR: String = format!("{}hub", *ROOT_CACHE_DIR);
pub static ref HUB_RT_CACHE_DIR: String = format!("{}hub_rt", *ROOT_CACHE_DIR);
}
pub fn write_file(dir: &str, path: &str, content: &str) -> error::Result<File> {
let path = format!("{}/{}", dir, path);
let mut file = File::create(&path).map_err(|e| {
tracing::error!("Failed to create file at {path}: {:?}", &e);
e
})?;
file.write_all(content.as_bytes())?;
file.flush()?;
Ok(file)View on GitHub (pinned to e474e8803c)
Solutions
- Remove the trailing slash from the WINDMILL_DIR value (e.g. /tmp/windmill instead of /tmp/windmill/)
- Sanitize the value in your Helm chart / config template before injecting it
- Note that the temp-dir default path already normalizes this for you — unset the var if you don't need a custom dir
Example fix
// before WINDMILL_DIR=/tmp/windmill/ // after WINDMILL_DIR=/tmp/windmill
Defensive patterns
Strategy: validation
Validate before calling
const dir = process.env.WINDMILL_DIR;
if (dir && /[\\/]$/.test(dir)) throw new Error(`WINDMILL_DIR must not end with a slash: ${dir}`); Prevention
- Normalize user-supplied paths (strip trailing slashes) before writing env config
- Add a lint check on Helm/compose templates for trailing slashes in path values
- On Windows, generate paths with a helper that omits the trailing separator
When it happens
Trigger: Setting `WINDMILL_DIR=/tmp/windmill/` (trailing slash) or a Windows path ending in a backslash in the environment of any Windmill binary.
Common situations: Copy-pasting a path with a trailing slash from a file manager; templating `WINDMILL_DIR: "{{ .Values.dir }}/"`; Windows bind mount paths like `C:\\windmill\\`.
Related errors
- WINDMILL_DIR must not be empty
- BASE_INTERNAL_URL is required in agent mode
- client build
- ${what} failed:\n${output}
- App ${appPath} not found
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c2a2fdef2b7079f7.
Report an issue: GitHub.