Hmbown/CodeWhale · error
lifecycle outbox queue is full; flush rejected
Error message
lifecycle outbox queue is full; flush rejected
What it means
enqueue pushes lifecycle events onto a bounded mpsc outbox queue (capacity OUTBOX_QUEUE_CAPACITY) and flush is rejected when the queue is full. The library refuses to enqueue (and thus flush) rather than blocking the caller, signaling backpressure as an explicit error.
Solutions
- Slow down or batch event production so the writer can drain the queue
- Check why the writer task is not draining (stuck I/O, task panic) and restart the component
- Increase OUTBOX_QUEUE_CAPACITY if the workload legitimately needs more buffer
Defensive patterns
Strategy: fallback
Validate before calling
// check queue pressure if the outbox exposes it
if outbox.approx_pending() >= OUTBOX_QUEUE_CAPACITY - 1 {
eprintln!("outbox near capacity; coalescing events");
} Try / catch
if let Err(e) = outbox.enqueue(event).await {
if e.to_string().contains("queue is full") {
// drop the event (it is already logged) or persist locally and flush later
dead_letter_log(event);
}
} Prevention
- Coalesce high-frequency lifecycle events before enqueue
- Alert when queue occupancy is persistently high
- Ensure the writer's downstream sink keeps up with production rate
When it happens
Trigger: Calling enqueue while the outbox's bounded channel already holds OUTBOX_QUEUE_CAPACITY pending events — the writer task is slower than producers or is not draining.
Common situations: Bursts of lifecycle events overwhelming the writer; the writer task stalled on slow I/O or a blocked downstream; very high event volume in a long-running session.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- background hook supervisor queue is full
- lifecycle outbox writer task is gone
- accepted_requests must equal requests_attempted; sender…
- another terminal clipboard write is still queued
- ChatGPT revoke task was lost
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/eebb0aa625701695.
Report an issue: GitHub.
Appendix: source
Thrown at crates/hooks/src/lifecycle_outbox.rs:242
///
/// Ordering: `send` happens before the spawn so events queued before the
/// writer starts are drained first, preserving enqueue order. The queue
/// is bounded: a wedged consumer drops further events with a warning
/// (observability, not control flow) but fails a flush fast instead of
/// dropping its reply channel.
fn enqueue(self: &Arc<Self>, command: OutboxCommand) -> Result<()> {
let is_flush = matches!(command, OutboxCommand::Flush(_));
match self.sender.try_send(command) {
Ok(()) => {}
Err(TrySendError::Full(_)) if !is_flush => {
tracing::warn!(
target: "lifecycle_outbox",
queue_capacity = OUTBOX_QUEUE_CAPACITY,
"lifecycle event dropped: outbox queue is full"
);
}
Err(TrySendError::Full(_)) => {
anyhow::bail!("lifecycle outbox queue is full; flush rejected");
}
Err(TrySendError::Closed(_)) => {
anyhow::bail!("lifecycle outbox writer task is gone");
}
}
self.ensure_writer_spawned();
Ok(())
}
fn ensure_writer_spawned(self: &Arc<Self>) {
if self.writer_spawned.load(Ordering::Acquire) {
return;
}
let _guard = self
.spawn_lock
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner());
if self.writer_spawned.load(Ordering::Acquire) {View on GitHub (pinned to 73e0f67d83)