abhigyanpatwari/GitNexus · warning
Worker ${workerIndex} timed out; retiring without immediate
Error message
Worker ${workerIndex} timed out; retiring without immediate terminate to avoid aborting native parser state. What it means
When a worker exceeds its idle/parse timeout, the pool retires it WITHOUT an immediate terminate(): terminating a worker mid-native-parser call risks the process-wide N-API abort (#2432). Instead the worker record is marked safeToTerminate: false, a safe-point promise is captured, listeners are armed, the worker is unref'd, and this warn records the retirement with the worker index and reason.
Source
Thrown at gitnexus/src/core/ingestion/workers/worker-pool.ts:1564
cleanupRetired();
};
const onRetiredMessageError = () => terminateWhenBackInJs();
const record: RetiredWorkerRecord = {
worker,
workerIndex,
reason,
cleanup: cleanupRetired,
terminate: terminateRetired,
safeToTerminate: false,
safePoint,
};
retiredWorkers.add(record);
worker.on('message', onRetiredMessage);
worker.once('error', onRetiredError);
worker.once('exit', onRetiredExit);
worker.once('messageerror', onRetiredMessageError);
(worker as Worker & { unref?: () => void }).unref?.();
logger.warn(
{ workerIndex, reason },
`Worker ${workerIndex} timed out; retiring without immediate terminate to avoid aborting native parser state.`,
);
};
const removeWorkerFromSlot = async (
workerIndex: number,
mode: WorkerRemovalMode,
reason: string,
): Promise<void> => {
const existing = workers[workerIndex];
workers[workerIndex] = undefined;
if (!existing) return;
if (mode === 'retire') {
retireWorkerAfterTimeout(existing, workerIndex, reason);
return;
}
// Recovery must settle before dispatch returns, but a failed threadView on GitHub (pinned to 0d1aed942f)
Solutions
- Identify the stalling file from the retirement reason / subsequent job warns and exclude or shrink it
- Raise GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS (or the configured idle timeout) if your hardware routinely needs longer per sub-batch
- Expect job-level handling to follow: the stalled job is split/retried/quarantined independently — this warn is about the worker, not the file outcome
- If retirements cluster on one language/grammar, check for a slow source-built native grammar and prefer the prebuilt binary
Example fix
# before export GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS= # default too low for big files → retire warn # after export GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS=120000 # sub-batches finish in-budget, no retire
Defensive patterns
Strategy: fallback
Validate before calling
// Budget timeouts to your hardware before the run: const slowCi = Number(process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS ?? 0) < 60000; if (slowCi) process.env.GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS = '120000';
Prevention
- Exclude or shrink files that stall sub-batches; retirement is the symptom, the file is the cause
- Track retire warns per language — clusters point at a slow source-built grammar (prefer prebuilts)
- Trust the no-immediate-terminate design: it prevents a process-wide N-API abort during retirement
When it happens
Trigger: A parse job blowing its timeout budget on a worker — the retire path fires: the slot is replaced by a fresh worker while the old one is drained/awaited at its safe point rather than killed; the warn names workerIndex and the timeout reason.
Common situations: Parser-hostile files (deeply nested/generated code) stalling a worker past GITNEXUS_WORKER_SUB_BATCH_TIMEOUT_MS, overloaded CI machines making legit parses look idle, or overly aggressive timeout overrides.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Worker ${workerIndex} parse job exhausted cumulative timeout
- Worker ${workerIndex} parse job idle timeout. Splitting into
- Worker ${workerIndex} parse job idle timeout (single item).
- Circuit '${key}' is open; retry in ${Math.ceil(retryAfterMs
- Request failed after retries (HTTP ${response.status})
AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-08-20).
Data as JSON: /api/errors/02b788eb12712ab1.
Report an issue: GitHub.