windmill-labs/windmill · error

Error occurred for HTTP route at route path: {}, error: {}

Error message

Error occurred for HTTP route at route path: {}, error: {}

What it means

HTTP trigger batch creation (create_many_http_triggers) wraps any per-trigger failure with the offending route path via this helper, producing 'Error occurred for HTTP route at route path: {path}, error: {cause}'. The wrapper preserves the underlying error (commonly uniqueness/duplicate-path violations) while identifying which route failed.

Source

Thrown at backend/windmill-trigger-http/src/handler.rs:254

        )
        .execute(&mut *tx)
        .await?;
    Ok(())
}

pub async fn create_many_http_triggers(
    authed: ApiAuthed,
    Extension(db): Extension<DB>,
    Extension(user_db): Extension<UserDB>,
    Path(w_id): Path<String>,
    Json(new_http_triggers): Json<Vec<TriggerData<HttpConfigRequest>>>,
) -> Result<(StatusCode, String)> {
    // Admin check for instance-wide routes is done per-trigger in insert_new_trigger_into_db

    let handler = HttpTrigger;

    let error_wrapper = |route_path: &str, error: Error| -> Error {
        anyhow::anyhow!(
            "Error occurred for HTTP route at route path: {}, error: {}",
            route_path,
            error
        )
        .into()
    };

    let mut route_path_keys = Vec::with_capacity(new_http_triggers.len());

    for new_http_trigger in new_http_triggers.iter() {
        // Per-item write scope, matching the single-create handler. The bulk
        // endpoint must not let a path-scoped token create triggers outside it.
        check_scopes(&authed, || {
            format!("http_triggers:write:{}", &new_http_trigger.base.path)
        })?;

        // This route inserts directly, bypassing the shared create handler.
        // `error_wrapper` would turn the rejection into a 500.

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read the wrapped {error} portion to identify the root cause (usually a duplicate-path DB conflict)
  2. Check existing HTTP triggers in the workspace and remove/rename the colliding path
  3. Use upsert semantics or delete the old trigger before re-creating in bulk
  4. Verify you are deploying to the intended workspace (path uniqueness is per workspace)
  5. Ensure proper admin permissions when registering instance-wide routes

Example fix

// before
POST /http_triggers/create_many  body: [{"path": "/api/x"}, {"path": "/api/x"}]
// after
POST /http_triggers/create_many  body: [{"path": "/api/x"}, {"path": "/api/y"}]
Defensive patterns

Strategy: validation

Validate before calling

// before creating, check path uniqueness in the workspace
const existing = await api.listHttpTriggers(workspace);
const taken = new Set(existing.map(t => `${t.method} ${t.path}`));
const clashes = triggers.filter(t => taken.has(`${t.method} ${t.path}`));
if (clashes.length) throw new Error(`routes already registered: ${clashes.map(c => c.path).join(", ")}`);

Try / catch

try {
  await api.createManyHttpTriggers(workspace, triggers);
} catch (e) {
  const m = String(e).match(/route path: ([^,]+), error: (.*)$/s);
  if (m) throw new Error(`failed to create route '${m[1]}': ${m[2]}`);
  throw e;
}

Prevention

When it happens

Trigger: POSTing multiple HTTP triggers where one or more route paths collide with an existing trigger's path (same workspace/method/path), or where insert_new_trigger_into_db fails validation for a specific path (e.g. instance-wide route admin check failing).

Common situations: Bulk-importing triggers that already exist; two triggers defined with the same path/method; case or trailing-slash variations of an existing path; deploying to a workspace that already has the route registered.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/6dccce24f98e79b5. Report an issue: GitHub.