ruvnet/ruflo · error · Error

Worker types must be a non-empty array

Error message

Worker types must be a non-empty array

What it means

WorkerQueue.registerWorker requires workerTypes to be a non-empty array of HeadlessWorkerType values ('audit', 'optimize', 'testgaps', 'document', 'ultralearn', 'refactor', 'deepdive', 'predict' per headless-worker-executor.ts). The guard rejects undefined, a single string, or an empty array [] before building the WorkerRegistration. This is the registration boundary for the distributed worker queue.

Source

Thrown at v3/@claude-flow/cli/src/services/worker-queue.ts:505

  // ============================================
  // Public API - Worker Management
  // ============================================

  /**
   * Register this instance as a worker
   */
  async registerWorker(
    workerTypes: HeadlessWorkerType[],
    options?: { maxConcurrent?: number; hostname?: string; containerId?: string }
  ): Promise<string> {
    // Initialize if needed
    if (!this.initialized) {
      await this.initialize();
    }

    // Validate worker types
    if (!Array.isArray(workerTypes) || workerTypes.length === 0) {
      throw new Error('Worker types must be a non-empty array');
    }

    this.maxConcurrent = options?.maxConcurrent || 1;

    const registration: WorkerRegistration = {
      workerId: this.workerId,
      workerTypes,
      maxConcurrent: this.maxConcurrent,
      currentTasks: 0,
      lastHeartbeat: new Date(),
      registeredAt: new Date(),
      hostname: options?.hostname,
      containerId: options?.containerId,
    };

    this.store.setWorker(this.workerId, registration);

    // Start heartbeat

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Pass a non-empty array: await queue.registerWorker(['audit', 'optimize'])
  2. If the list comes from config, validate it is non-empty at load time with a clear 'no worker types configured' error
  3. Wrap a single value in an array rather than passing the string directly
  4. Check for accidental array destruction — spread or .map() bugs that yield [] or undefined

Example fix

// before
const types = cfg.workers?.filter(w => w.enabled).map(w => w.type);
await queue.registerWorker(types); // [] when everything is disabled -> throws

// after
const types = cfg.workers?.filter(w => w.enabled).map(w => w.type) ?? [];
if (types.length === 0) throw new Error('No enabled worker types in config');
await queue.registerWorker(types);
Defensive patterns

Strategy: validation

Validate before calling

const types = candidateTypes.filter(isHeadlessWorkerType); // narrow to the union first
if (!Array.isArray(types) || types.length === 0) {
  throw new Error('Cannot register worker: no valid headless worker types supplied');
}
await queue.registerWorker(types);

Type guard

const HEADLESS_WORKER_TYPES = ['audit', 'optimize', 'testgaps', 'document', 'ultralearn', 'refactor', 'deepdive', 'predict'] as const;

function isHeadlessWorkerType(value: unknown): value is (typeof HEADLESS_WORKER_TYPES)[number] {
  return typeof value === 'string' && (HEADLESS_WORKER_TYPES as readonly string[]).includes(value);
}

Prevention

When it happens

Trigger: Calling registerWorker([]) when a filter produced no types; passing a bare string ('audit') instead of ['audit']; a variable that was never initialized (undefined) reaching the call; spreading an optional config array that was absent (...(cfg?.types ?? [])) yielding an empty array.

Common situations: Registering workers dynamically from config where the list can legitimately be empty; refactors that changed the parameter from a single type to an array; optional-chaining defaults that silently produce [] instead of failing early at the source.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/328bd652006f2042. Report an issue: GitHub.