mastra-ai/mastra · error · Error

IssueReconcileWorker: call init() before start()

Error message

IssueReconcileWorker: call init() before start()

What it means

IssueReconcileWorker follows a two-phase lifecycle: init(deps) stores the worker dependencies and resolves the lease provider from deps.pubsub, and start() begins the scheduling loop. start() guards on this.deps; if init() was never called the worker has no logger, lease provider, or storage access and cannot run, so it throws a directive message naming the required call order.

Source

Thrown at mastracode/factory/src/integrations/issue-reconcile-worker.ts:54

    this.#integrationId = config.integrationId;
    this.name = `${config.integrationId}-issue-reconcile`;
    this.#leaseKey = `${config.integrationId}:issue-reconcile`;
    this.#reconcile = config.reconcile;
    this.#intervalMs = config.intervalMs ?? DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;
    if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {
      throw new Error(`${config.integrationId} issue reconcile interval must be a positive number.`);
    }
    this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);
  }

  async init(deps: WorkerDeps): Promise<void> {
    await super.init(deps);
    this.#leaseProvider = getLeaseProvider(deps.pubsub);
  }

  async start(): Promise<void> {
    if (this.#running) return;
    if (!this.deps) throw new Error('IssueReconcileWorker: call init() before start()');
    this.#running = true;
    this.deps.logger.info(`${this.#integrationId} issue reconcile worker started`, { intervalMs: this.#intervalMs });
    this.#schedule(0);
  }

  async stop(): Promise<void> {
    if (!this.#running) return;
    this.#running = false;
    if (this.#timer) clearTimeout(this.#timer);
    this.#timer = undefined;
    await this.#inFlight;
  }

  get isRunning(): boolean {
    return this.#running;
  }

  #schedule(delayMs: number): void {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Call await worker.init(deps) before await worker.start() in the bootstrap/worker-manager code
  2. Ensure init() failure handling re-runs init(), not just start(), when restarting a worker
  3. Add a lifecycle helper (e.g. workerManager.register(worker)) that enforces init-then-start ordering
  4. In tests, use a setup helper that constructs and inits the worker so start() is never called bare

Example fix

// before
const worker = new IssueReconcileWorker({ integrationId: 'github', reconcile });
await worker.start(); // throws: init() not called
// after
const worker = new IssueReconcileWorker({ integrationId: 'github', reconcile });
await worker.init({ pubsub, logger, storage });
await worker.start();
Defensive patterns

Strategy: try-catch

Validate before calling

if (!worker.deps) {
  throw new Error('Worker not initialized — call await worker.init(deps) before start().');
}

Type guard

function isInitialized(worker: IssueReconcileWorker): boolean {
  return Boolean((worker as unknown as { deps?: unknown }).deps);
}

Try / catch

try {
  await worker.start();
} catch (err) {
  if ((err as Error).message.includes('call init() before start()')) {
    await worker.init(workerDeps);
    await worker.start();
  } else throw err;
}

Prevention

When it happens

Trigger: Calling worker.start() directly after construction without first awaiting worker.init(deps) — or calling init() and start() but start() racing/overriding an earlier failure in init.

Common situations: New worker wired into a bootstrap that only calls start(); test code constructs the worker and immediately starts it; lifecycle refactor moved dependency injection from start() into init() and old call sites weren't updated; init() threw earlier (e.g. bad interval config) and a retry path calls start() without re-initing.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/3fd15d3294ad74ad. Report an issue: GitHub.