windmill-labs/windmill · error
Module '{}': Exponential backoff base (seconds) must be grea
Error message
Module '{}': Exponential backoff base (seconds) must be greater than 0. A base of 0 would cause immediate retries. What it means
Flow validation checks each module's retry policy. An exponential backoff policy with attempts > 0 but a base of 0 seconds is invalid because the base is the initial delay multiplier — with 0 every retry fires immediately with no backoff, so validation rejects the flow.
Source
Thrown at backend/windmill-types/src/flows.rs:212
schema: self.schema,
tag: self.tag,
dedicated_worker: self.dedicated_worker,
timeout: self.timeout,
deployment_message: self.deployment_message,
visible_to_runner_only: self.visible_to_runner_only,
on_behalf_of_email: self.on_behalf_of_email,
on_behalf_of: self.on_behalf_of,
preserve_on_behalf_of: self.preserve_on_behalf_of,
ws_error_handler_muted: self.ws_error_handler_muted,
labels: self.labels,
skip_draft_deletion: self.skip_draft_deletion,
}
}
}
fn validate_retry(retry: &Retry, module_id: &str) -> anyhow::Result<()> {
if retry.exponential.attempts > 0 && retry.exponential.seconds == 0 {
return Err(anyhow::anyhow!(
"Module '{}': Exponential backoff base (seconds) must be greater than 0. A base of 0 would cause immediate retries.",
module_id
));
}
Ok(())
}
/// Script/sub-flow step references must be workspace paths (`u/`, `f/`, `g/`) or a hub
/// reference (`hub/`). Empty is tolerated for intermediate/incomplete steps. This blocks
/// absolute or local filesystem paths (e.g. `/tmp/.../ops/scripts/...` baked in by a
/// `wmill sync push` from a feature-branch checkout) from being persisted into a flow,
/// where they silently mis-resolve to an unrelated script at runtime (#9751).
fn is_workspace_runnable_path(path: &str) -> bool {
path.is_empty()
|| path.starts_with("u/")
|| path.starts_with("f/")
|| path.starts_with("g/")
|| path.starts_with("hub/")View on GitHub (pinned to e474e8803c)
Solutions
- Set retry.exponential.seconds to a positive value (e.g. 1) whenever attempts > 0
- If retries aren't wanted, set exponential.attempts to 0 instead of leaving seconds at 0
- Validate the flow JSON locally before deploying
Example fix
// before
"retry": {"exponential": {"attempts": 3, "seconds": 0}}
// after
"retry": {"exponential": {"attempts": 3, "seconds": 1}} Defensive patterns
Strategy: validation
Validate before calling
function validateRetry(retry) {
if (retry?.exponential?.attempts > 0 && retry.exponential.seconds <= 0)
throw new Error("exponential backoff base (seconds) must be > 0 when attempts > 0");
} Prevention
- When setting exponential attempts, always set seconds (e.g. 1) together
- Use the flow editor's retry form rather than raw JSON where possible
- Add a shared retry-config builder that defaults seconds > 0
When it happens
Trigger: Saving or validating a flow (validate_flow_value, called on flow create/update) where any module has retry.exponential.attempts set to a positive number while retry.exponential.seconds is 0.
Common situations: Building flows via API/CLI where the retry object is partially filled (attempts set, seconds left at default 0), UI form bugs, or copying retry configs between fixed-interval and exponential retry types.
Related errors
- Invalid AI agent provider configuration: ${errors.join('\n')
- Module "${args.module_id}" is not an inline rawscript in flo
- Module "${args.module_id}" is not an inline rawscript in flo
- 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/eeb01e9427bebe50.
Report an issue: GitHub.