abhigyanpatwari/GitNexus · error · WorkerPoolDispatchError
Worker pool circuit breaker tripped${reason}. Subsequent dis
Error message
Worker pool circuit breaker tripped${reason}. Subsequent dispatches require a fresh pool instance. What it means
Thrown by `dispatch()` when the pool's circuit breaker has already tripped (`poolBroken === true`). The circuit breaker is set when the pool suffers a catastrophic, non-recoverable failure; once set, every subsequent dispatch to the SAME pool instance re-throws this `WorkerPoolDispatchError`. The pool is dead — the message explicitly states that subsequent dispatches require a fresh pool instance. The error carries the triggering `poolFailure.message` as the reason.
Source
Thrown at gitnexus/src/core/ingestion/workers/worker-pool.ts:1282
).then(() => undefined);
const dispatch = async <TInput, TResult>(
items: TInput[],
onProgress?: (filesProcessed: number) => void,
chunkHash?: string,
): Promise<TResult[]> => {
// Await the initial-spawn readiness gate (F13). On first dispatch
// this blocks for up to poolOptions.workerReadyTimeoutMs while every initial
// worker's `{type:'ready'}` handshake is checked; on subsequent
// dispatches the promise is already settled and resolves
// synchronously. Slots whose initial worker crashed in top-of-
// script init have been dropped from `activeSlots` by the gate
// before this point — they don't surface here as "no active
// workers" until *all* initial slots fail.
await initialReadyGate;
if (poolBroken) {
const reason = poolFailure ? `: ${poolFailure.message}` : '';
throw new WorkerPoolDispatchError(
`Worker pool circuit breaker tripped${reason}. ` +
`Subsequent dispatches require a fresh pool instance.`,
[],
);
}
if (items.length === 0) return [];
if (activeSlots.size === 0) {
const detail =
initialReadinessFailures.length > 0
? ` after initial ready handshake: ${initialReadinessFailures.join('; ')}`
: '';
// The bounded self-heal exhausted (or short-circuited a deterministic
// crash-loop). Classify automatically so the caller renders the real
// cause without consulting any operator flag (#1741).
const crashClass: StartupCrashClass = deterministicStartupDetected
? 'deterministic-startup'
: 'transient-exhausted';
throw new WorkerPoolInitializationError(View on GitHub (pinned to d540b00184)
Solutions
- Create a FRESH pool instance (`createWorkerPool(...)`) before dispatching again — a broken pool cannot be reset.
- Inspect the `reason` (the original `poolFailure.message`) to fix the underlying cause before recreating the pool.
- After a dispatch throws, always discard the pool reference and rebuild it for the next batch rather than retrying on the same instance.
Example fix
// before — reuse a pool after it broke
const pool = createWorkerPool(url);
try { await pool.dispatch(batchA); } catch { /* swallowed */ }
await pool.dispatch(batchB); // → Worker pool circuit breaker tripped...
// after — recreate the pool after a failure
let pool = createWorkerPool(url);
try {
await pool.dispatch(batchA);
} catch {
pool = createWorkerPool(url); // fresh instance
}
await pool.dispatch(batchB); Defensive patterns
Strategy: fallback
Type guard
import { WorkerPoolDispatchError } from 'gitnexus/dist/core/ingestion/workers/worker-pool.js';
function isPoolBroken(err): err is WorkerPoolDispatchError {
return err instanceof WorkerPoolDispatchError
|| /circuit breaker tripped/i.test(err.message);
} Try / catch
// Recreate the pool after a circuit-breaker trip — a broken pool is not reusable.
let pool = createWorkerPool(url);
for (const batch of batches) {
try {
await pool.dispatch(batch);
} catch (err) {
if (/circuit breaker tripped/i.test(err.message)) {
pool = createWorkerPool(url); // fresh instance, fix root cause first
continue;
}
throw err;
}
} Prevention
- Never reuse a pool after a dispatch throws a WorkerPoolDispatchError — discard and recreate it.
- Inspect the `reason` in the message to fix the underlying pool failure before recreating.
- Scope a pool to one logical batch group so a breaker trip only invalidates that group.
When it happens
Trigger: Calling `pool.dispatch(...)` a second (or later) time after the pool already broke during a prior dispatch — e.g. an unrecoverable worker-death cascade tripped the breaker, and the caller did not recreate the pool before the next chunk dispatch.
Common situations: A parse loop that reuses one pool across many chunks and continues dispatching after an earlier chunk's fatal pool failure; a caller that swallowed a prior dispatch error without checking whether the pool was still usable.
Related errors
- Circuit '${key}' is open; retry in ${Math.ceil(retryAfterMs
- Circuit '${key}' is open; retry in ${Math.ceil(halfOpenRetry
- hf-circuit-open: HuggingFace download circuit is open after
- hf-circuit-open: HuggingFace download circuit opened after 3
- Worker pool has no active workers${detail}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/6b46ea86deb7ada5.
Report an issue: GitHub.