t8y2/dbx · error
SQLite worker has no open database
Error message
SQLite worker has no open database
What it means
The SQLite worker's Query operation was received while no database connection is open. The worker protocol requires an Open (or successful open path) before Query; otherwise it replies with this error body instead of panicking on a null connection.
Source
Thrown at crates/dbx-sqlite-worker/src/runtime.rs:48
if matches!(response.body, WorkerBody::Ok { .. }) {
// keep serving
}
}
Ok(())
}
fn handle(connection: &mut Option<Connection>, request: WorkerRequest) -> WorkerResponse {
let body = match request.op {
WorkerOp::Open { path } => match open_database(&path) {
Ok(opened) => {
*connection = Some(opened);
WorkerBody::ok()
}
Err(error) => WorkerBody::err(error),
},
WorkerOp::Query { sql, max_rows } => match connection.as_mut() {
Some(conn) => query(conn, &sql, max_rows.unwrap_or(10_000)),
None => WorkerBody::err("SQLite worker has no open database"),
},
WorkerOp::Backup { dest } => match connection.as_mut() {
Some(conn) => backup(conn, &dest),
None => WorkerBody::err("SQLite worker has no open database"),
},
WorkerOp::Restore { src } => match connection.as_mut() {
Some(conn) => restore(conn, &src),
None => WorkerBody::err("SQLite worker has no open database"),
},
WorkerOp::Ping => WorkerBody::pong(),
WorkerOp::Close => {
*connection = None;
WorkerBody::ok()
}
};
WorkerResponse { id: request.id, body }
}
View on GitHub (pinned to c0390bff16)
Solutions
- Send WorkerOp::Open with a valid database path before any Query
- Check the result of the Open op and handle its error before proceeding
- If a Close was issued, reopen before issuing further ops
- Pool workers so each op sequence starts with a successful open
Example fix
// before
send(Query { sql }); // no prior open
// after
send(Open { path: "app.db" });
send(Query { sql }); Defensive patterns
Strategy: type-guard
Validate before calling
fn require_open(worker: &WorkerHandle) -> Result<(), &'static str> {
if worker.last_op_was_successful_open() { Ok(()) } else { Err("worker has no open database") }
} Type guard
type OpenWorker = WorkerHandle;
fn as_open(worker: &WorkerHandle) -> Option<&OpenWorker> {
worker.is_open().then_some(worker)
} Try / catch
match worker.send(WorkerOp::Query { sql, max_rows: None }).await {
Err(body) if body.error() == Some("SQLite worker has no open database") => {
worker.send(WorkerOp::Open { path }).await?;
worker.send(WorkerOp::Query { sql, max_rows: None }).await?
}
other => other?,
} Prevention
- Always Open before other ops; check the Open result
- Track worker state client-side (opened/closed)
- Reopen after Close or after any failed op
- Encapsulate op sequences behind a helper that guarantees open-then-act
When it happens
Trigger: Sending WorkerOp::Query before WorkerOp::Open; after a Close operation; after a failed/aborted open; reusing a worker whose connection was never established because an earlier open errored.
Common situations: Client code that skips the open step assuming auto-connect; connection lost/closed by an earlier failed operation; test harnesses exercising ops without setup.
Related errors
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/b3ad2d32269d14c7.
Report an issue: GitHub.