affaan-m/ECC · critical · anyhow::Error
DB writer channel closed
Error message
DB writer channel closed
What it means
The DbRuntime sends database write commands through an mpsc channel to a dedicated DB writer task. If the channel's receiver is dropped — meaning the writer task has exited or panicked — send() fails and the function returns this error. All subsequent DB operations for this session are broken because there is no writer to process them.
Source
Thrown at ecc2/src/session/runtime.rs:71
}
async fn append_output_line(&self, stream: OutputStream, line: String) -> Result<()> {
self.send(|ack| DbMessage::AppendOutputLine { stream, line, ack })
.await
}
async fn touch_heartbeat(&self) -> Result<()> {
self.send(|ack| DbMessage::TouchHeartbeat { ack }).await
}
async fn send<F>(&self, build: F) -> Result<()>
where
F: FnOnce(oneshot::Sender<DbAck>) -> DbMessage,
{
let (ack_tx, ack_rx) = oneshot::channel();
self.tx
.send(build(ack_tx))
.map_err(|_| anyhow::anyhow!("DB writer channel closed"))?;
match ack_rx.await {
Ok(Ok(())) => Ok(()),
Ok(Err(error)) => Err(anyhow::anyhow!(error)),
Err(_) => Err(anyhow::anyhow!("DB writer acknowledgement dropped")),
}
}
}
fn run_db_writer(db_path: PathBuf, session_id: String, mut rx: mpsc::UnboundedReceiver<DbMessage>) {
let (opened, open_error) = match StateStore::open(&db_path) {
Ok(db) => (Some(db), None),
Err(error) => (None, Some(error.to_string())),
};
while let Some(message) = rx.blocking_recv() {
match message {
DbMessage::UpdateState { state, ack } => {View on GitHub (pinned to 01e15490f0)
Solutions
- Check logs from run_db_writer for panic or DB open errors
- Verify the DB file path is accessible and not locked by another process
- Ensure the Tokio runtime is not being shut down prematurely while sessions are active
- Restart the session if the writer task has died — the channel cannot be reopened
- Monitor DB writer task health and abort sessions whose writer has failed
Defensive patterns
Strategy: try-catch
Try / catch
match db_runtime.touch_heartbeat().await {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("DB writer channel closed") => {
tracing::error!("DB writer task has died; session DB operations are broken");
Err(e)
}
Err(e) => Err(e),
} Prevention
- Monitor DB writer task health and abort sessions whose writer has failed
- Ensure the Tokio runtime is not shut down while sessions are active
- Check DB file accessibility and disk space to prevent writer-task panics
- Implement a writer-task supervisor that restarts the writer on failure
When it happens
Trigger: The DB writer task (run_db_writer) has exited due to a panic, DB open failure, or runtime shutdown, and a DbRuntime method (touch_heartbeat, etc.) attempts to send a message through the closed channel.
Common situations: DB writer task panicked during a write operation (e.g., SQLite locked, disk full). Tokio runtime was shut down while sessions are still active. DB file was deleted or moved while the writer was running.
Related errors
- The local Itô CLI could not be started: ${result.error.messa
- A normalized install request is required
- Unsupported install request mode: ${request.mode}
- Canonical session snapshot requires workers[${index}].runtim
- Missing value for --db
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/3d99a74b723f2066.
Report an issue: GitHub.