windmill-labs/windmill · critical
BASE_INTERNAL_URL is required in agent mode
Error message
BASE_INTERNAL_URL is required in agent mode
What it means
In agent mode the binary acts as a remote agent that calls back to a Windmill server, so it must know the server's internally reachable address. `Mode` parsing in windmill-common panics when `MODE=agent` is set but `BASE_INTERNAL_URL` is unset — the agent cannot function without knowing where to reach the server.
Source
Thrown at backend/windmill-common/src/utils.rs:125
pub static ref MODE_AND_ADDONS: ModeAndAddons = {
let mut search_addon = false;
let mode = std::env::var("MODE")
.map(|x| x.to_lowercase())
.map(|x| {
if &x == "server" {
println!("Binary is in 'server' mode");
Mode::Server
} else if &x == "worker" {
tracing::info!("Binary is in 'worker' mode");
#[cfg(windows)]
{
println!("It is highly recommended to use the agent mode instead on windows (MODE=agent) and to pass a BASE_INTERNAL_URL");
}
Mode::Worker
} else if &x == "agent" {
println!("Binary is in 'agent' mode with BASE_INTERNAL_URL={}", std::env::var("BASE_INTERNAL_URL").unwrap_or_default());
if std::env::var("BASE_INTERNAL_URL").is_err() {
panic!("BASE_INTERNAL_URL is required in agent mode")
}
if std::env::var("AGENT_TOKEN").is_err() {
println!("AGENT_TOKEN is not passed. This is required for the agent to work and contains the JWT to authenticate with the server.")
}
#[cfg(not(feature = "enterprise"))]
{
panic!("Agent mode is only available in the EE, ignoring...");
}
#[cfg(feature = "enterprise")]
Mode::Agent
} else if &x == "indexer" {
tracing::info!("Binary is in 'indexer' mode");
#[cfg(not(feature = "tantivy"))]
{
eprintln!("Cannot start the indexer because tantivy is not included in this binary/image. Make sure you are using the EE image if you want to access the full text search features.");
panic!("Indexer mode requires compiling with the tantivy feature flag.");
}View on GitHub (pinned to e474e8803c)
Solutions
- Set BASE_INTERNAL_URL to the server's address reachable from the agent (e.g. https://windmill.example.com)
- Also set AGENT_TOKEN — it is required for authentication and only warns if missing, but the agent will not work without it
- If you only need a worker and not an agent, use MODE=worker instead
Example fix
// before MODE=agent // after MODE=agent BASE_INTERNAL_URL=https://windmill.example.com AGENT_TOKEN=<jwt>
Defensive patterns
Strategy: validation
Validate before calling
# preflight before launching in agent mode
if [ "$MODE" = "agent" ]; then
[ -n "$BASE_INTERNAL_URL" ] || { echo "agent mode requires BASE_INTERNAL_URL" >&2; exit 1; }
[ -n "$AGENT_TOKEN" ] || { echo "agent mode requires AGENT_TOKEN" >&2; exit 1; }
curl -fsS "$BASE_INTERNAL_URL/api/health" >/dev/null || { echo 'BASE_INTERNAL_URL unreachable'; exit 1; }
fi Prevention
- Template BASE_INTERNAL_URL and AGENT_TOKEN into every agent deployment manifest
- Smoke-test server reachability from the agent network before rollout
- Document that agents also need AGENT_TOKEN even though its absence only warns
When it happens
Trigger: Starting the binary with `MODE=agent` and no `BASE_INTERNAL_URL` environment variable defined.
Common situations: Deploying agents in EE setups and forgetting the env var; copying worker config to an agent without adding BASE_INTERNAL_URL; URL set only in a compose file that the agent container doesn't inherit.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Agent mode is only available in the EE, ignoring...
- WINDMILL_DIR must not be empty
- Server mode requires a database connection
- WINDMILL_DIR must not end with a trailing slash, got: {dir}
- ${what} failed:\n${output}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/83c6f244b703bcf3.
Report an issue: GitHub.