{"record":{"id":"3fd15d3294ad74ad","repo":"mastra-ai/mastra","slug":"issuereconcileworker-call-init-before-start","errorCode":null,"errorMessage":"IssueReconcileWorker: call init() before start()","messagePattern":"IssueReconcileWorker: call init\\(\\) before start\\(\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/issue-reconcile-worker.ts","lineNumber":54,"sourceCode":"    this.#integrationId = config.integrationId;\n    this.name = `${config.integrationId}-issue-reconcile`;\n    this.#leaseKey = `${config.integrationId}:issue-reconcile`;\n    this.#reconcile = config.reconcile;\n    this.#intervalMs = config.intervalMs ?? DEFAULT_ISSUE_RECONCILE_INTERVAL_MS;\n    if (!Number.isFinite(this.#intervalMs) || this.#intervalMs <= 0) {\n      throw new Error(`${config.integrationId} issue reconcile interval must be a positive number.`);\n    }\n    this.#leaseTtlMs = Math.max(MIN_LEASE_TTL_MS, this.#intervalMs * 3);\n  }\n\n  async init(deps: WorkerDeps): Promise<void> {\n    await super.init(deps);\n    this.#leaseProvider = getLeaseProvider(deps.pubsub);\n  }\n\n  async start(): Promise<void> {\n    if (this.#running) return;\n    if (!this.deps) throw new Error('IssueReconcileWorker: call init() before start()');\n    this.#running = true;\n    this.deps.logger.info(`${this.#integrationId} issue reconcile worker started`, { intervalMs: this.#intervalMs });\n    this.#schedule(0);\n  }\n\n  async stop(): Promise<void> {\n    if (!this.#running) return;\n    this.#running = false;\n    if (this.#timer) clearTimeout(this.#timer);\n    this.#timer = undefined;\n    await this.#inFlight;\n  }\n\n  get isRunning(): boolean {\n    return this.#running;\n  }\n\n  #schedule(delayMs: number): void {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/issue-reconcile-worker.ts#L36-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Call await worker.init(deps) before await worker.start() in the bootstrap/worker-manager code","Ensure init() failure handling re-runs init(), not just start(), when restarting a worker","Add a lifecycle helper (e.g. workerManager.register(worker)) that enforces init-then-start ordering","In tests, use a setup helper that constructs and inits the worker so start() is never called bare"],"exampleFix":"// before\nconst worker = new IssueReconcileWorker({ integrationId: 'github', reconcile });\nawait worker.start(); // throws: init() not called\n// after\nconst worker = new IssueReconcileWorker({ integrationId: 'github', reconcile });\nawait worker.init({ pubsub, logger, storage });\nawait worker.start();","handlingStrategy":"try-catch","validationCode":"if (!worker.deps) {\n  throw new Error('Worker not initialized — call await worker.init(deps) before start().');\n}","typeGuard":"function isInitialized(worker: IssueReconcileWorker): boolean {\n  return Boolean((worker as unknown as { deps?: unknown }).deps);\n}","tryCatchPattern":"try {\n  await worker.start();\n} catch (err) {\n  if ((err as Error).message.includes('call init() before start()')) {\n    await worker.init(workerDeps);\n    await worker.start();\n  } else throw err;\n}","preventionTips":["Wrap worker construction+init+start in a single bootstrap helper to enforce ordering","Always await init() before start(); never fire-and-forget init","When restarting after an init failure, re-run init() before start()","Add a unit test asserting start() without init() throws, and a lifecycle test for the happy path"],"tags":["worker","lifecycle","initialization"],"backgroundTag":"init-not-called","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}