mastra-ai/mastra · error

Invalid model string format: "${config}". Expected format: "

Error message

Invalid model string format: "${config}". Expected format: "mastra/provider/model"

What it means

The embedding model router parses model strings into provider/model (or gateway/provider/model) identifiers. When the string starts with the Mastra gateway id ('mastra'), it requires at least 3 slash-separated segments; otherwise it throws 'Invalid model string format: "<config>". Expected format: "mastra/provider/model"'. This guard exists because gateway model IDs may themselves contain slashes, so the remainder is re-joined with parts.slice(1).

Source

Thrown at packages/core/src/llm/model/embedding-router.ts:140

  // spec). This wrapper keeps exposing the V2 interface; doEmbed adapts.
  private providerModel: EmbeddingModelV3;

  constructor(config: string | OpenAICompatibleConfig) {
    // Normalize config to always have provider and model IDs
    let normalizedConfig: {
      providerId: string;
      modelId: string;
      url?: string;
      apiKey?: string;
      headers?: Record<string, string>;
    };

    if (typeof config === 'string') {
      // Parse provider/model or gateway/provider/model from string.
      const parts = config.split('/');
      if (parts[0] === MASTRA_GATEWAY_ID) {
        if (parts.length < 3) {
          throw new Error(`Invalid model string format: "${config}". Expected format: "mastra/provider/model"`);
        }
        normalizedConfig = { providerId: MASTRA_GATEWAY_ID, modelId: parts.slice(1).join('/') };
      } else {
        if (parts.length !== 2) {
          throw new Error(`Invalid model string format: "${config}". Expected format: "provider/model"`);
        }
        const [providerId, modelId] = parts as [string, string];
        normalizedConfig = { providerId, modelId };
      }
    } else if ('providerId' in config && 'modelId' in config) {
      normalizedConfig = {
        providerId: config.providerId,
        modelId: config.modelId,
        url: config.url,
        apiKey: config.apiKey,
        headers: config.headers,
      };
    } else {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Use the full three-segment format: 'mastra/<provider>/<model>', e.g. 'mastra/openai/text-embedding-3-small'
  2. If not using the Mastra gateway, drop the 'mastra/' prefix and pass '<provider>/<model>' instead
  3. Log/print the config value being passed to catch dynamic string-building bugs
  4. Validate the model string with a regex before constructing the router

Example fix

// before
new EmbeddingRouter('mastra/openai'); // throws
// after
new EmbeddingRouter('mastra/openai/text-embedding-3-small');
Defensive patterns

Strategy: validation

Validate before calling

function assertModelString(config) {
  const parts = config.split('/');
  if (parts[0] === 'mastra') {
    if (parts.length < 3) throw new Error(`Invalid model string: "${config}". Expected "mastra/provider/model"`);
  } else if (parts.length !== 2) {
    throw new Error(`Invalid model string: "${config}". Expected "provider/model"`);
  }
}
assertModelString(modelConfig); // call before constructing the router

Type guard

function isValidModelString(config) {
  if (typeof config !== 'string') return false;
  const parts = config.split('/');
  return parts[0] === 'mastra' ? parts.length >= 3 : parts.length === 2;
}

Try / catch

try {
  const router = new EmbeddingRouter(config);
} catch (e) {
  if (e.message.startsWith('Invalid model string format')) {
    console.error(`Bad MODEL env/config: ${config}. Use "provider/model" or "mastra/provider/model".`);
    process.exit(1);
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Constructing an embedding model/router with a string like 'mastra/openai' (only 2 segments) or 'mastra' alone, i.e. any 'mastra/...' string without a provider AND model segment after the gateway id.

Common situations: Migrating from 'provider/model' strings to gateway format and dropping a segment; assuming 'mastra/provider' is enough; dynamically building the model string and truncating the model id; typos like 'mastra/openai/text-embedding-3/' — those parse, but 'mastra/openai' does not.

Related errors


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