{"record":{"id":"d8c284d3fa3c1594","repo":"mastra-ai/mastra","slug":"mastrafactory-finalize-called-before-prepare","errorCode":null,"errorMessage":"MastraFactory.finalize() called before prepare()","messagePattern":"MastraFactory\\.finalize\\(\\) called before prepare\\(\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/factory.ts","lineNumber":999,"sourceCode":"\n    return {\n      ...prepared.mastraArgs,\n      // Same provider on `studio.auth` as on `server.auth` (buildServerConfig):\n      // deployed factories must authenticate BOTH plain API callers and Studio\n      // requests (`x-mastra-client-type: studio` routes to `studio.auth`).\n      ...(auth ? { studio: { auth } } : {}),\n      ...(integrationWorkers.length > 0 ? { workers: integrationWorkers } : {}),\n    };\n  }\n\n  /**\n   * Post-construct boot: initialize the controller (which inherits the\n   * constructed Mastra's storage) and start its workers. Call AFTER the entry\n   * has run `new Mastra(prepare()'s args)`.\n   */\n  async finalize(): Promise<void> {\n    if (!this.#prepared) {\n      throw new Error('MastraFactory.finalize() called before prepare()');\n    }\n    await timedPhase('finalize.controller', () => this.#prepared!.finalize());\n    await timedPhase(\n      'finalize.reconcileBoundThreads',\n      () => this.#factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),\n    );\n    this.#dispatcher?.start();\n  }\n\n  /** Stop Factory-owned background dispatch before the host process shuts down. */\n  async shutdown(): Promise<void> {\n    await this.#dispatcher?.stop();\n  }\n}\n","sourceCodeStart":981,"sourceCodeEnd":1014,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/factory.ts#L981-L1014","documentation":"finalize() is the post-construct boot step: it initializes the factory controller (which inherits the constructed Mastra's storage) and starts its workers, and must run after the entry file has executed new Mastra(prepare()'s args). It checks the internal #prepared flag and throws if prepare() has not successfully completed, since finalize would otherwise boot a controller against uninitialized state.","triggerScenarios":"Calling await factory.finalize() before (or instead of) calling await factory.prepare() and constructing new Mastra(args) — e.g. skipping prepare in a script, or ordering finalize before prepare in the entry file.","commonSituations":"Writing a standalone migration/CLI script that calls finalize directly; reordering statements during a refactor so finalize runs first; copying the finalize call into a new entry file without the prepare + new Mastra sequence.","solutions":["Call prepare() first, construct the Mastra instance with its returned args, then call finalize(): const args = await factory.prepare(); const mastra = new Mastra(args); await factory.finalize();","Ensure the ordering in your entry file: prepare → new Mastra(args) → finalize.","If this is a short-lived script, decide whether you need finalize at all — it boots controller workers meant for a running server.","Check that hot-reload or lazy-init logic isn't invoking finalize before the prepare promise resolves."],"exampleFix":"// before\nawait factory.finalize(); // throws\n\n// after\nconst args = await factory.prepare();\nexport const mastra = new Mastra(args);\nawait factory.finalize();","handlingStrategy":"try-catch","validationCode":"// enforce the startup sequence in a helper\nexport async function bootFactory(config) {\n  const factory = new MastraFactory(config);\n  const args = await factory.prepare();\n  const mastra = new Mastra(args);\n  await factory.finalize();\n  return { factory, mastra };\n}","typeGuard":"// only finalize after prepare has resolved and Mastra was constructed\nlet prepared = false;\nasync function safeFinalize(factory) {\n  if (!prepared) throw new Error('finalize() requires prepare() + new Mastra(args) first');\n  return factory.finalize();\n}","tryCatchPattern":"try {\n  await factory.finalize();\n} catch (err) {\n  if (err.message.includes('called before prepare()')) {\n    throw new Error('Boot order bug: run prepare() and new Mastra(args) before finalize()', { cause: err });\n  }\n  throw err;\n}","preventionTips":["Use a single bootFactory() helper that encodes the prepare → Mastra → finalize order","Never call finalize() in scripts or code paths that skip prepare()","Keep entry files linear: no conditional or reordered boot steps","Add a smoke test that boots the app through the shared helper"],"tags":["lifecycle","initialization-order","api-misuse"],"backgroundTag":"initialization-order","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}