mastra-ai/mastra · error
MastraFactory.finalize() called before prepare()
Error message
MastraFactory.finalize() called before prepare()
What it means
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.
Source
Thrown at mastracode/factory/src/factory.ts:999
return {
...prepared.mastraArgs,
// Same provider on `studio.auth` as on `server.auth` (buildServerConfig):
// deployed factories must authenticate BOTH plain API callers and Studio
// requests (`x-mastra-client-type: studio` routes to `studio.auth`).
...(auth ? { studio: { auth } } : {}),
...(integrationWorkers.length > 0 ? { workers: integrationWorkers } : {}),
};
}
/**
* Post-construct boot: initialize the controller (which inherits the
* constructed Mastra's storage) and start its workers. Call AFTER the entry
* has run `new Mastra(prepare()'s args)`.
*/
async finalize(): Promise<void> {
if (!this.#prepared) {
throw new Error('MastraFactory.finalize() called before prepare()');
}
await timedPhase('finalize.controller', () => this.#prepared!.finalize());
await timedPhase(
'finalize.reconcileBoundThreads',
() => this.#factoryProcessor?.reconcileAllBoundThreads() ?? Promise.resolve(),
);
this.#dispatcher?.start();
}
/** Stop Factory-owned background dispatch before the host process shuts down. */
async shutdown(): Promise<void> {
await this.#dispatcher?.stop();
}
}
View on GitHub (pinned to 75dd419e61)
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.
Example fix
// before await factory.finalize(); // throws // after const args = await factory.prepare(); export const mastra = new Mastra(args); await factory.finalize();
Defensive patterns
Strategy: try-catch
Validate before calling
// enforce the startup sequence in a helper
export async function bootFactory(config) {
const factory = new MastraFactory(config);
const args = await factory.prepare();
const mastra = new Mastra(args);
await factory.finalize();
return { factory, mastra };
} Type guard
// only finalize after prepare has resolved and Mastra was constructed
let prepared = false;
async function safeFinalize(factory) {
if (!prepared) throw new Error('finalize() requires prepare() + new Mastra(args) first');
return factory.finalize();
} Try / catch
try {
await factory.finalize();
} catch (err) {
if (err.message.includes('called before prepare()')) {
throw new Error('Boot order bug: run prepare() and new Mastra(args) before finalize()', { cause: err });
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- MastraAuthBetterAuth is not initialized — init() must run fi
- Shared browser not launched. Call createSharedSession() firs
- GithubReconcileWorker: call init() before start()
- Browser not launched
- App deletion failed: ${data.error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/d8c284d3fa3c1594.
Report an issue: GitHub.