Hmbown/CodeWhale · warning · BackgroundSupervisorFailure::Full

background hook supervisor queue is full

Error message

background hook supervisor queue is full

What it means

A background hook could not be submitted because the background hook supervisor's queue was full. The failure is recorded in the hook result's error field with success=false rather than panicking or blocking. It indicates backpressure: hooks are being produced faster than the supervisor executes them.

Solutions

  1. Slow down or reduce the number of hooks registered in configuration.
  2. Find and fix slow/stuck hook commands that are occupying queue slots (check hook stderr/durations in results).
  3. Increase the background supervisor queue capacity if your workload legitimately enqueues many hooks.
  4. Retry the hook; the failure is recorded per-submission and does not corrupt supervisor state.

Example fix

// hook config: reduce fire frequency
// before: run hook on every PostToolUse event
// after: debounce or restrict matcher to the specific tools you need
"matcher": "Bash"
Defensive patterns

Strategy: fallback

Try / catch

let result = run_hook_background(cmd);
if !result.success && result.error == Some("background hook supervisor queue is full".into()) {
    run_hook_synchronously(cmd); // degrade to inline execution
}

Prevention

When it happens

Trigger: Submitting a background hook when BackgroundSupervisorFailure::Full is returned — the supervisor's bounded channel has no free slots at submission time (executor.rs hook submission path).

Common situations: Many hooks firing in rapid succession (e.g. on every tool call) while hook commands run slowly; a stuck or very slow hook command clogging the queue; hook queue capacity configured too small for the workload.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/60e4accf5c49f41a. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/hooks/executor.rs:2456

            label: sanitize_hook_label(hook.name.as_deref()),
            timeout: Duration::from_secs(self.effective_timeout_secs(hook)),
            plugin_authority: hook.plugin_authority.clone(),
            project_authority: hook.project_authority.clone(),
        });

        // The result describes the bounded submission, not the run: no caller
        // can mistake "queued" for "exited 0".
        HookResult {
            name: hook.name.clone(),
            background: true,
            strict: false,
            success: submission.is_ok(),
            exit_code: None,
            stdout: String::new(),
            stderr: String::new(),
            duration: started.elapsed(),
            error: submission.err().map(|failure| match failure {
                BackgroundSupervisorFailure::Full => {
                    "background hook supervisor queue is full".to_string()
                }
                BackgroundSupervisorFailure::Disconnected => {
                    "background hook supervisor is unavailable".to_string()
                }
            }),
        }
    }

    /// The timeout actually applied to a hook, foreground or background.
    ///
    /// `[hooks].default_timeout_secs` *replaces* the per-hook value when set;
    /// that is the shipped behavior and is documented as such in
    /// `docs/HOOKS.md`.
    fn effective_timeout_secs(&self, hook: &Hook) -> u64 {
        self.config.effective_timeout_secs(hook)
    }
}

View on GitHub (pinned to 73e0f67d83)