mastra-ai/mastra · error

Expected format azure-openai/deployment-name, but got ${rout

Error message

Expected format azure-openai/deployment-name, but got ${routerId}

What it means

Azure OpenAI router ids use a 2-part format "azure-openai/deployment-name" (the deployment name is the modelId). If the prefix check passes but everything after "azure-openai/" is empty, there is no deployment to resolve and the function throws.

Source

Thrown at packages/core/src/llm/model/gateway-resolver.ts:19

export type ResolvedModelConfig = {
  url: string | false;
  headers: Record<string, string>;
  resolvedModelId: string;
  fullModelId: string;
};

export function parseModelRouterId(routerId: string, gatewayPrefix?: string): { providerId: string; modelId: string } {
  if (gatewayPrefix && !routerId.startsWith(`${gatewayPrefix}/`)) {
    throw new Error(`Expected ${gatewayPrefix}/ in model router ID ${routerId}`);
  }

  const idParts = routerId.split('/');

  // Azure OpenAI uses 2-part format (azure-openai/deployment), others use 3-part (gateway/provider/model)
  if (gatewayPrefix === 'azure-openai') {
    const modelId = idParts.slice(1).join('/');
    if (!modelId) {
      throw new Error(`Expected format azure-openai/deployment-name, but got ${routerId}`);
    }
    return {
      providerId: 'azure-openai',
      modelId, // Deployment name
    };
  }

  // Provider-equals-gateway: a gateway whose provider id is the same as its
  // gateway id (e.g. amazon-bedrock) uses a 2-part router id (gateway/model),
  // because there is no separate provider segment to namespace. Catalog ids
  // for such gateways are always two parts (model ids contain no slashes).
  if (gatewayPrefix && idParts.length === 2 && idParts[0] === gatewayPrefix) {
    const modelId = idParts[1];
    if (!modelId) {
      throw new Error(`Expected format ${gatewayPrefix}/model, but got ${routerId}`);
    }
    return {
      providerId: gatewayPrefix,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Provide the deployment name: "azure-openai/your-deployment".
  2. Validate the deployment variable is non-empty before building the id.
  3. Check for accidental trailing slashes when concatenating the id.

Example fix

// before
parseModelRouterId(`azure-openai/${deployment}`, "azure-openai"); // deployment === ""
// after
if (!deployment) throw new Error("deployment is required");
parseModelRouterId(`azure-openai/${deployment}`, "azure-openai");
Defensive patterns

Strategy: validation

Validate before calling

const deployment = 'my-embedding-deployment';
if (!deployment) throw new Error('Azure deployment name is required');
const routerId = `azure-openai/${deployment}`;
parseModelRouterId(routerId, 'azure-openai');

Type guard

const isValidAzureRouterId = (id) => id.startsWith('azure-openai/') && id.length > 'azure-openai/'.length;

Try / catch

try {
  const { providerId, modelId } = parseModelRouterId(routerId, 'azure-openai');
} catch (e) {
  if (e instanceof Error && e.message.includes('azure-openai/deployment-name')) {
    console.error(`Azure router id needs a deployment name: "${routerId}"`);
  } else throw e;
}

Prevention

When it happens

Trigger: parseModelRouterId("azure-openai/", "azure-openai") or parseModelRouterId("azure-openai", "azure-openai") — an id whose deployment segment is missing/empty.

Common situations: Deployment name field left blank in stored config; trailing slash without a name; template strings where the deployment variable was undefined/empty.

Related errors


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