t8y2/dbx · critical · DuckDbWorkerError
duckdb_worker_exited
duckdb_worker_exited
Error message
DuckDB worker process exited
What it means
When the DuckDB worker process dies unexpectedly, spawn_stdout_reader (triggered from ensure_started_locked) fails over by resolving every pending request of the dead generation with a duckdb_worker_exited error, so callers' promises reject instead of hanging. The error indicates the worker subprocess terminated (crash, OOM kill, signal) before responding.
Source
Thrown at crates/dbx-core/src/db/duckdb_worker_process.rs:789
Ok(None) => break,
Err(err) => {
log::warn!("[duckdb-worker:stdout-error] error={err}");
break;
}
}
}
let pending = {
let mut pending = pending.lock().await;
let ids = pending
.iter()
.filter(|&(_id, request)| request.generation == generation)
.map(|(id, _request)| id.clone())
.collect::<Vec<_>>();
ids.into_iter().filter_map(|id| pending.remove(&id).map(|request| (id, request.sender))).collect::<Vec<_>>()
};
for (id, sender) in pending {
let _ = sender.send(DuckDbWorkerResponse::err(
id,
DuckDbWorkerError::new("duckdb_worker_exited", "DuckDB worker process exited"),
));
}
});
}
View on GitHub (pinned to c0390bff16)
Solutions
- Retry the failed request: implement restart-on-demand by re-calling the ensure/start path, which respawns a fresh worker and re-runs the query.
- Check why the child died: inspect worker stderr/core logs for panics, and cap query memory (memory_limit pragma) to avoid OOM kills.
- Handle the duckdb_worker_exited rejection in callers with a bounded retry + backoff and surface a user-facing reconnect message if retries exhaust.
Example fix
// before
const res = await worker.request(q); // rejects with duckdb_worker_exited and gives up
// after
try {
const res = await worker.request(q);
} catch (e) {
if (e.code === "duckdb_worker_exited") {
await worker.restart();
return worker.request(q);
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// TS: health-check the worker before dispatching
async function ensureAlive(worker: DuckDbWorkerProcess) {
if (!(await worker.ping())) await worker.ensureStarted();
} Type guard
function isExitedError(e: unknown): e is { code: "duckdb_worker_exited" } {
return typeof e === "object" && e !== null && (e as any).code === "duckdb_worker_exited";
} Try / catch
try {
return await worker.request(req);
} catch (e) {
if (isExitedError(e)) {
await worker.restart();
return worker.request(req);
}
throw e;
} Prevention
- Set a DuckDB memory_limit to avoid OOM kills of the worker process.
- Monitor worker stderr and restart-on-crash automatically.
- Treat duckdb_worker_exited as retryable once after a fresh spawn; alert if it recurs.
When it happens
Trigger: A request sent through duckdb_worker_process (crates/dbx-core/src/db/duckdb_worker_process.rs:789) whose worker process exited while the request was pending — child crash (panic/segfault), SIGKILL from the OOM killer on a huge query, or explicit kill on shutdown/generation change.
Common situations: Out-of-memory on large DuckDB aggregations; worker panic on malformed input; system shutdown or supervisor restart killing the child; generation bump from a previous restart invalidating in-flight requests.
Related errors
- agent exited before {method}
- agent exited before ready
- agent exited during {method}
- duckdb_worker_busy
- invalid_json
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/e0be7a8a0cf5eb78.
Report an issue: GitHub.