windmill-labs/windmill · error
sql job on http connection
Error message
sql job on http connection
What it means
Jobs are pulled from the database either through the internal SQL connection or via the HTTP API. `extract_job_and_perms` extracts job permissions using the connection that matches the job kind: SQL jobs require a Connection::Sql (direct database handle) to read their perms. If a SQL job arrives over an HTTP connection there is no DB handle to authorize it, so the process panics — this is an internal invariant, meaning a routing bug rather than user error.
Source
Thrown at backend/windmill-worker/src/worker.rs:1990
windmill_common::log_context::spawn_with_log_context(async move {
async move {
match insert_wait_time(job_id, root_job_id, &db, wait_time).await {
Ok(()) => tracing::warn!("job {job_id} waited for an executor for a significant amount of time. Recording value wait_time={}ms", wait_time),
Err(e) => tracing::error!("Failed to insert outstanding wait time: {}", e),
}
}
.instrument(span)
.await
});
}
}
async fn extract_job_and_perms(job: NextJob, conn: &Connection) -> JobAndPerms {
match (job, conn) {
(NextJob::Sql { job, flow_runners, .. }, Connection::Sql(db)) => {
JobAndPerms { flow_runners, ..job.get_job_and_perms(db).await }
}
(NextJob::Sql { .. }, Connection::Http(_)) => panic!("sql job on http connection"),
(NextJob::Http(job), _) => job,
}
}
pub fn create_span_with_name(
arc_job: &MiniPulledJob,
worker_name: &str,
hostname: Option<&str>,
span_name: &str,
) -> Span {
// The span macro requires a literal, so we use a fixed name and set otel.name dynamically
let span = tracing::span!(
tracing::Level::INFO,
"job",
job_id = %arc_job.id,
root_job = field::Empty,
workspace_id = %arc_job.workspace_id,
worker = %worker_name,View on GitHub (pinned to e474e8803c)
Solutions
- Report this to Windmill maintainers with worker logs — it indicates a job-routing bug, not a misconfiguration
- Ensure workers that can execute SQL jobs pull through the SQL connection path (not HTTP-only)
- Check your worker capability configuration (which queues/kinds the worker pulls) matches the deployed job kinds
- If running a modified build, fix the dispatch so NextJob::Sql is only matched with Connection::Sql
Example fix
// before: pulling sql jobs over http connection let job = pull_job(&Connection::Http(client), ...); // after: pull sql jobs with the sql connection let job = pull_job(&Connection::Sql(db), ...);
Defensive patterns
Strategy: validation
Validate before calling
// When integrating job pulls, assert kind/connection compatibility first
function canPull(jobKind, conn) {
return !(jobKind === 'sql' && conn.type !== 'sql');
} Type guard
function isSqlJobOnHttp(job, conn) {
return job && job.kind === 'Sql' && conn && conn.type === 'http';
} Prevention
- Keep job-pull connection type and worker capabilities in sync
- Add unit tests covering every (NextJob variant, Connection variant) pair
- Alert on this panic in production — it signals a dispatch bug, not user error
- Avoid HTTP-only pull paths for SQL-capable workers when forking/extending the puller
When it happens
Trigger: A NextJob::Sql job dispatched to a worker/runner whose connection is Connection::Http — i.e. the job puller fetched a SQL job on the HTTP path, typically after a code change in job dispatch or mismatched worker capabilities.
Common situations: Custom forks/patches to the pull loop mixing job kinds and connection types; running a worker configured for HTTP job pull that receives SQL jobs due to a dispatch/queue misconfiguration; developing a new job kind and wiring it through the wrong connection variant.
Related errors
- could not create dir '{directory_path}': {e}
- failed to execute replace_ephemeral command: {}
- ENABLE_UNSHARE_PID is set but unshare test failed. Error: {}
- ENABLE_UNSHARE_PID is set but unshare binary not found. Inst
- ENABLE_UNSHARE_PID is set but failed to test unshare: {}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/90ed929f12300c97.
Report an issue: GitHub.