mastra-ai/mastra · error
Invalid model id: ${modelId}
Error message
Invalid model id: ${modelId} What it means
resolveModel parses a model id as `provider/rest-of-path` after stripping gateway/custom-provider prefixes. If either the provider segment or the remainder (bareModelId) is empty, the id is malformed and 'Invalid model id' is thrown. This includes ids with no slash at all (e.g. 'gpt-4o').
Source
Thrown at mastracode/sdk/src/agents/model.ts:117
? modelId.slice(MASTRACODE_GATEWAY_ID.length + 1)
: modelId;
// Deployed web registers a custom providers source (DB-backed, tenant
// scoped); when registered it is authoritative and settings.json custom
// providers are ignored. Undefined = local settings-based behavior.
const customProviders = resolveCustomProviders(options?.requestContext) ?? settings.customProviders;
// Ids selected from the shared /models catalog were previously persisted in
// the gateway-qualified `mastracode/<customProviderId>/<model>` form, which
// parses the provider as `mastracode` and breaks provider config lookup.
// Normalize at resolution time (in addition to stripping at selection time)
// so already-saved ids and any surface that persists the raw catalog id
// still resolve to the custom provider.
const normalizedInput = stripMastraCodeCustomProviderPrefix(bedrockNormalizedInput, customProviders);
const isMastraGatewayModel = normalizedInput.startsWith(MASTRA_GATEWAY_PREFIX);
const normalizedModelId = stripMastraGatewayPrefix(normalizedInput);
const [providerId, ...modelParts] = normalizedModelId.split('/');
const bareModelId = modelParts.join('/');
if (!providerId || !bareModelId) {
throw new Error(`Invalid model id: ${modelId}`);
}
if (providerId === AMAZON_BEDROCK_GATEWAY_ID) {
const bedrockGateway = createAmazonBedrockGateway();
const routerId = `${AMAZON_BEDROCK_GATEWAY_ID}/${bareModelId}`;
const auth = bedrockGateway.resolveAuth({
gatewayId: AMAZON_BEDROCK_GATEWAY_ID,
providerId: AMAZON_BEDROCK_GATEWAY_ID,
modelId: bareModelId,
routerId,
});
return bedrockGateway.resolveLanguageModel({
providerId: AMAZON_BEDROCK_GATEWAY_ID,
modelId: bareModelId,
apiKey: auth?.apiKey ?? '',
headers,
});
}View on GitHub (pinned to 75dd419e61)
Solutions
- Provide the full `provider/model-id` form, e.g. 'openai/gpt-4o' or 'anthropic/claude-sonnet-4'
- Check the model config/env for an empty or whitespace-only value and set a valid id
- If using gateway prefixes, keep the provider segment after the prefix (e.g. 'mastra/gateway/openai/gpt-4o' style per convention)
- Log the raw modelId before resolveModel to see what is actually being passed
Example fix
// before model: 'gpt-4o' // after model: 'openai/gpt-4o'
Defensive patterns
Strategy: validation
Validate before calling
const VALID = /^[a-z0-9-]+\/.+$/i;
if (!VALID.test(modelId)) throw new Error(`model id must be provider/model, got: ${modelId}`); Type guard
const isProviderQualified = (id: string): boolean =>
id.includes('/') && id.split('/').every(p => p.length > 0); Try / catch
try {
const model = resolveModel(modelId);
} catch (err) {
if ((err as Error).message.startsWith('Invalid model id')) {
console.error(`Use provider/model form, e.g. openai/gpt-4o (got "${modelId}")`);
} else throw err;
} Prevention
- Validate model ids against a known provider list at config load time
- Never store bare model names in configs; always qualify with provider
- Trim/normalize model id inputs before resolveModel
When it happens
Trigger: resolveModel (via getObserverModel/getReflectorModel/getDynamicModel/etc.) receives a modelId that after normalization has no `provider/model` structure: empty string, bare model name without a slash, 'provider/' with empty remainder, or just '/'-degenerate strings.
Common situations: Writing 'gpt-4o' instead of 'openai/gpt-4o', config files with a blank or whitespace model field, accidentally deleting the provider prefix during edits, or copying an id with a trailing slash.
Related errors
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
- Expected a PEM-encoded public key or certificate string for
- terminationGraceMs must be greater than zero.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/1f6d9088ce6dd3c2.
Report an issue: GitHub.