mastra-ai/mastra · error

MastraFactory: 'storage' is required. Pass a FactoryStorage

Error message

MastraFactory: 'storage' is required. Pass a FactoryStorage backend — e.g. new PgFactoryStorage({ connectionString }) from '@mastra/pg' for deployments, or new LibSQLFactoryStorage({ url }) from '@mastra/libsql' for local dev.

What it means

The MastraFactory constructor requires a persistent FactoryStorage backend because the factory seeds a runtime registry and must persist state across processes/replicas. The constructor throws immediately when config.storage is missing, with guidance naming the two supported backends: PgFactoryStorage from '@mastra/pg' for deployments and LibSQLFactoryStorage from '@mastra/libsql' for local development. This is a fail-fast config validation so the app never boots half-configured.

Source

Thrown at mastracode/factory/src/factory.ts:292

  for (const parent of KNOWN_PLATFORM_COOKIE_PARENTS) {
    // Exact match → we're already on the parent, host-only is correct.
    // Subdomain match → mint the parent-scoped cookie.
    if (hostname === parent) return undefined;
    if (hostname.endsWith(`.${parent}`)) return `.${parent}`;
  }
  return undefined;
}

export class MastraFactory {
  readonly #config: MastraFactoryConfig;
  #prepared: Awaited<ReturnType<typeof prepareAgentControllerMount>> | undefined;
  #dispatcher: FactoryDecisionDispatcher | undefined;
  #factoryProcessor: FactoryPhaseStateProcessor | undefined;
  #preparing = false;

  constructor(config: MastraFactoryConfig) {
    if (!config?.storage) {
      throw new Error(
        "MastraFactory: 'storage' is required. Pass a FactoryStorage backend — e.g. " +
          "new PgFactoryStorage({ connectionString }) from '@mastra/pg' for deployments, or " +
          "new LibSQLFactoryStorage({ url }) from '@mastra/libsql' for local dev.",
      );
    }
    this.#config = config;
  }

  /**
   * Resolve feature readiness, wire every dependency explicitly, and assemble
   * everything needed to construct the server-owned Mastra. Returns the args
   * for the `new Mastra(...)` literal that must live in the entry file.
   */
  async prepare(): Promise<MastraArgs> {
    // Guard set synchronously (before the first await) so overlapping calls —
    // not just strictly sequential ones — can't double-seed the runtime
    // registry or double-run one-time adapter init.
    if (this.#preparing) throw new Error('MastraFactory.prepare() called twice');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Create a storage backend and pass it: storage: new LibSQLFactoryStorage({ url: 'file:./factory.db' }) for local dev, or storage: new PgFactoryStorage({ connectionString: process.env.DATABASE_URL }) for deployments.
  2. Install the matching package: pnpm add @mastra/libsql (local) or pnpm add @mastra/pg (deployed).
  3. Verify the config object passed to new MastraFactory() is not null/undefined and includes the storage key.
  4. For tests, use an in-memory/ephemeral file LibSQL url rather than omitting storage.

Example fix

// before
const factory = new MastraFactory({
  publicUrl: 'https://factory.example.com',
});

// after
import { PgFactoryStorage } from '@mastra/pg';
const factory = new MastraFactory({
  publicUrl: 'https://factory.example.com',
  storage: new PgFactoryStorage({ connectionString: process.env.DATABASE_URL }),
});
Defensive patterns

Strategy: validation

Validate before calling

import { PgFactoryStorage } from '@mastra/pg';
if (!process.env.DATABASE_URL) throw new Error('DATABASE_URL is required for factory storage');
const factory = new MastraFactory({
  ...config,
  storage: new PgFactoryStorage({ connectionString: process.env.DATABASE_URL }),
});
if (!factory) throw new Error('MastraFactory construction failed');

Type guard

function hasStorage(config) {
  return config != null && typeof config === 'object' && 'storage' in config && config.storage != null;
}
if (!hasStorage(factoryConfig)) throw new Error('MastraFactoryConfig.storage is required');

Try / catch

let factory;
try {
  factory = new MastraFactory(config);
} catch (err) {
  if (err.message.includes("'storage' is required")) {
    throw new Error('Startup config error: supply a FactoryStorage backend (@mastra/pg or @mastra/libsql)', { cause: err });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling new MastraFactory(config) where config is null/undefined or config.storage is undefined — e.g. building the config object conditionally and omitting storage, or passing only publicUrl/allowedOrigins/integrations.

Common situations: Following outdated docs or examples from before storage became mandatory; constructing the factory in a test harness with a minimal config; forgetting to instantiate a storage backend because the import from '@mastra/pg' or '@mastra/libsql' was removed during a refactor.

Related errors


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