abhigyanpatwari/GitNexus · error · WorkerPoolDisabledError

Worker-pool parsing cannot be disabled (${reason}). GitNexus

Error message

Worker-pool parsing cannot be disabled (${reason}). GitNexus no longer has a sequential parser — the worker pool self-heals via quarantine + respawn, so there is no slower path to fall back to. Pass `--workers <N>` with N>=1, or omit it for an auto-sized pool.

What it means

Thrown by the parse phase when the worker pool is explicitly disabled. GitNexus removed its sequential (in-process) parser, so the worker pool — with quarantine, respawn, and a circuit breaker — is the ONLY parse path. There is no slower fallback to silently degrade to, so the three legacy disable channels (`skipWorkers: true`, `--workers 0`/`workerPoolSize=0`, and `GITNEXUS_WORKER_POOL_SIZE=0`) are now hard configuration errors instead of feature switches. The check only fires when there are parseable files; a repo with zero parseable files is exempt.

Source

Thrown at gitnexus/src/core/ingestion/pipeline-phases/parse-impl.ts:553

    });
  }

  // Sequential parsing has been removed: the worker pool (quarantine +
  // respawn/recycle + circuit breaker) is the sole parse path. The three
  // channels that used to select an in-process parser are now hard errors, so
  // an operator who set one gets an actionable message instead of a silently
  // slower (now nonexistent) fallback. Validated before any chunk work; a
  // zero-parseable-file repo is exempt (nothing to parse).
  if (totalParseable > 0) {
    const requestedPoolSize = options?.workerPoolSize;
    const disabledByEnv = requestedPoolSize === undefined && workerPoolDisabledByEnv();
    if (options?.skipWorkers || requestedPoolSize === 0 || disabledByEnv) {
      const reason = options?.skipWorkers
        ? '`skipWorkers: true` was passed'
        : requestedPoolSize === 0
          ? '`--workers 0` (workerPoolSize=0) was requested'
          : '`GITNEXUS_WORKER_POOL_SIZE=0` is set';
      throw new WorkerPoolDisabledError(
        `Worker-pool parsing cannot be disabled (${reason}). GitNexus no longer ` +
          `has a sequential parser — the worker pool self-heals via quarantine + ` +
          `respawn, so there is no slower path to fall back to. Pass ` +
          `\`--workers <N>\` with N>=1, or omit it for an auto-sized pool.`,
      );
    }
  }

  // Build byte-budget chunks. The budget is resolved per-call (U14): options
  // first, then env, then the built-in default. Pre-U14 this was a
  // module-load IIFE constant, which froze the env value at import time
  // and made `PipelineOptions.chunkByteBudget` silently no-op on warm test
  // runs. Resolving in the function body restores per-call configurability
  // and matches the pattern used by resolveAutoPoolSize and the U1
  // parseChunkConcurrency resolver.
  // Effective worker count, computed up-front so the chunk budget can scale to
  // keep the whole pool busy (#worker-idle). The pool is ALWAYS used (sequential
  // parsing was removed; the disabled channels threw above). Size it to the

View on GitHub (pinned to d540b00184)

Solutions

  1. Pass `--workers <N>` with N>=1, or omit `--workers` entirely so the pool auto-sizes to `os.availableParallelism() - 1` (clamped to the cap).
  2. Unset `GITNEXUS_WORKER_POOL_SIZE` from the environment (check `.env`, CI config, shell profiles) if you did not set it explicitly.
  3. Remove `skipWorkers: true` from the `PipelineOptions` object you pass to the analyze API.
  4. If you genuinely need single-worker parsing for debugging, pass `--workers 1` rather than disabling the pool.

Example fix

// before
const options = { skipWorkers: true };
await analyze(repo, options); // throws WorkerPoolDisabledError

// after — let the pool auto-size
const options = {};
await analyze(repo, options);

// or pin to a single worker for debugging
const options = { workerPoolSize: 1 };
Defensive patterns

Strategy: validation

Validate before calling

// Before calling analyze, validate the worker-pool config
import { workerPoolDisabledByEnv } from 'gitnexus/dist/core/ingestion/workers/worker-pool.js';

function assertWorkerPoolUsable(options) {
  if (options?.skipWorkers) {
    throw new Error('Refusing to analyze: skipWorkers is set but the worker pool is the only parser.');
  }
  if (options?.workerPoolSize === 0) {
    throw new Error('Refusing to analyze: workerPoolSize=0 is not allowed.');
  }
  if (options?.workerPoolSize === undefined && workerPoolDisabledByEnv()) {
    throw new Error('Refusing to analyze: GITNEXUS_WORKER_POOL_SIZE=0 is set in the environment.');
  }
}

assertWorkerPoolUsable(options);
await analyze(repo, options);

Type guard

// Narrow PipelineOptions to ensure the pool is not disabled
type WorkerPoolSafeOptions = {
  skipWorkers?: false;
  workerPoolSize?: number; // must be >= 1
};
function isWorkerPoolSafe(o): o is WorkerPoolSafeOptions {
  return o.skipWorkers !== true && o.workerPoolSize !== 0;
}

Try / catch

try {
  await analyze(repo, options);
} catch (err) {
  if (err.name === 'WorkerPoolDisabledError') {
    // config error — fix the flag/env and re-run, do not retry as-is
    console.error(err.message);
    process.exit(2);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `analyze`/`processParsing` with `PipelineOptions.skipWorkers = true`; passing `--workers 0` on the CLI (workerPoolSize=0); or having `GITNEXUS_WORKER_POOL_SIZE=0` set in the environment while no explicit positive `workerPoolSize` is passed — all only when `totalParseable > 0`.

Common situations: An operator who read old docs sets `GITNEXUS_WORKER_POOL_SIZE=0` to debug single-threaded parsing (that path no longer exists). A CI script pins `--workers 0` to reduce memory. A test harness passes `skipWorkers: true` expecting the legacy in-process fallback. An upgrade from an older GitNexus version leaves the now-invalid env var exported in a shell profile.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/2be48aba0a56d81f. Report an issue: GitHub.