windmill-labs/windmill · error
EXIT_AFTER_N_JOBS must be a positive integer (or 0 to disabl
Error message
EXIT_AFTER_N_JOBS must be a positive integer (or 0 to disable), got '{v}' What it means
`validate_worker_lifecycle_env` checks the EXIT_AFTER_N_JOBS environment variable at worker startup. If the variable is set but not parseable as a u64 (empty string counts as unset here and is fine), the worker refuses to start. Fail-fast is deliberate: silently ignoring an unparseable value would leave a worker that was supposed to recycle after N jobs running forever, defeating the deployment's restart guarantee.
Source
Thrown at backend/windmill-common/src/worker.rs:498
.and_then(|x| x.parse::<bool>().ok())
.unwrap_or(false);
// Features flags:
pub static ref DISABLE_FLOW_SCRIPT: bool = std::env::var("DISABLE_FLOW_SCRIPT").ok().is_some_and(|x| x == "1" || x == "true");
pub static ref ROOT_STANDALONE_BUNDLE_DIR: String = format!("{}/.windmill/standalone_bundle", std::env::var("HOME").unwrap_or_else(|_| "/root".to_string()));
}
lazy_static::lazy_static! {
pub static ref ROOT_CACHE_NOMOUNT_DIR: String = format!("{}/cache_nomount/", *WINDMILL_DIR);
}
/// Refuses to start on an `EXIT_AFTER_N_JOBS` that does not parse. Silently ignoring it
/// would leave a worker meant to recycle its environment running forever without doing so,
/// which is exactly the guarantee the deployment set it for.
pub fn validate_worker_lifecycle_env() -> anyhow::Result<()> {
match std::env::var("EXIT_AFTER_N_JOBS") {
Ok(v) if !v.is_empty() && v.parse::<u64>().is_err() => Err(anyhow::anyhow!(
"EXIT_AFTER_N_JOBS must be a positive integer (or 0 to disable), got '{v}'"
)),
_ => Ok(()),
}
}
/// Whether native mode is forced by the environment (NATIVE_MODE=true env var or WORKER_GROUP=native).
/// This does NOT account for native_mode set in the DB worker group config — for that, read
/// `WORKER_CONFIG.native_mode` which combines all sources.
pub fn is_native_mode_from_env() -> bool {
*NATIVE_MODE || *WORKER_GROUP == "native"
}
/// True iff this process is configured to act as the production cloud cluster:
/// `CLOUD_HOSTED=true` AND `BASE_URL`'s host matches `CLOUD_PRODUCTION_HOST`.
/// Centralized so the API setter, the runtime pull path, and any future cloud-
/// only feature share one canonical check (rather than re-implementing the
/// scheme/host parser at each call site).View on GitHub (pinned to e474e8803c)
Solutions
- Set EXIT_AFTER_N_JOBS to a plain non-negative integer, e.g. `EXIT_AFTER_N_JOBS=100` (0 disables the exit-after-N behavior).
- Remove surrounding whitespace/quotes from the value in your env file or manifest.
- Check for templating artifacts: rendered values like `100.0` or `nil` must be corrected to integers.
- Unset the variable entirely if you do not want lifecycle-based recycling.
Example fix
// before (values.yaml env) - name: EXIT_AFTER_N_JOBS value: "50.0" // after - name: EXIT_AFTER_N_JOBS value: "50"
Defensive patterns
Strategy: validation
Validate before calling
const raw = process.env.EXIT_AFTER_N_JOBS;
if (raw !== undefined && raw !== "" && !/^\d+$/.test(raw)) {
throw new Error(`EXIT_AFTER_N_JOBS must be a non-negative integer, got '${raw}'`);
} Try / catch
try {
startWorker();
} catch (e) {
if (String(e).includes("EXIT_AFTER_N_JOBS")) {
console.error(`Fix EXIT_AFTER_N_JOBS: '${process.env.EXIT_AFTER_N_JOBS}' is not an integer. Use e.g. 100, or 0/unset to disable.`);
process.exit(1);
}
throw e;
} Prevention
- Always set EXIT_AFTER_N_JOBS as a bare integer string, e.g. "100".
- Quote-free plain values in env files; avoid floats, units, or negatives.
- Check rendered k8s/Helm templates for formatting artifacts ("50.0", empty strings).
- Unset the variable rather than setting it to an unparseable placeholder when recycling is not wanted.
When it happens
Trigger: Setting `EXIT_AFTER_N_JOBS=ten`, `EXIT_AFTER_N_JOBS=5.0`, `EXIT_AFTER_N_JOBS=" 10"`, `EXIT_AFTER_N_JOBS=-3` (negative), or any non-integer value, then starting a worker — `windmill_main` calls the validator and aborts on error.
Common situations: Using a float or unit-suffixed value ('50 jobs'); negative numbers assumed valid; shell quoting leaving stray spaces; Helm/k8s templates rendering numbers as strings with formatting; YAML `EXIT_AFTER_N_JOBS: 010` confusion is fine but `" "` whitespace-only strings fail parse.
Related errors
- WORKER_SUFFIX must only contain ASCII letters, digits and un
- WORKER_SUFFIX must be at most {MAX_WORKER_SUFFIX_LABEL_LEN}
- Invalid AI agent provider configuration: ${errors.join('\n')
- API key or resource path is required
- Missing a model to test
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/c5c229c76232d3e1.
Report an issue: GitHub.