mastra-ai/mastra · error · MastraError
AGENT_FS_ROUTING_INSTRUCTIONS_INVALID
AGENT_FS_ROUTING_INSTRUCTIONS_INVALID
Error message
Agent "${name}": agents/${name}/instructions.ts must default-export a string, a system message, an array of either, or a function returning one, but got ${received}. What it means
When an Agent is defined via filesystem routing, packages/core reads agents/<name>/instructions.ts and expects its default export to be a string, a system message object, an array of those, or a function returning one of those. assertValidInstructionsModule (via resolveInstructions) inspects the runtime value of the default export and throws this error when none of the supported shapes match. It is a USER-category configuration error: the instructions file exists but its export shape is not usable.
Source
Thrown at packages/core/src/agent/fs-routing/index.ts:487
* no default export at all never reaches here; the bundler fails first, naming
* the same file.)
*/
function assertValidInstructionsModule(
name: string,
instructions: unknown,
): asserts instructions is DynamicArgument<AgentInstructions> {
const isUsable =
typeof instructions === 'function' ||
(Array.isArray(instructions)
? instructions.length > 0 && instructions.every(isUsableSystemMessage)
: isUsableSystemMessage(instructions));
if (isUsable) {
return;
}
const received = describeInstructionsExport(instructions);
throw new MastraError({
id: 'AGENT_FS_ROUTING_INSTRUCTIONS_INVALID',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { agentName: name, received },
text: `Agent "${name}": agents/${name}/instructions.ts must default-export a string, a system message, an array of either, or a function returning one, but got ${received}.`,
});
}
/**
* One entry of an `AgentInstructions` value: a bare string, or a system message
* whose `content` is a string. Anything else reaches the model as an empty
* string, so the entries have to be checked rather than just the container —
* `[123]` is exactly as mute as `123`.
*/
function isUsableSystemMessage(value: unknown): boolean {
return (
typeof value === 'string' ||
(typeof value === 'object' && value !== null && typeof (value as { content?: unknown }).content === 'string')View on GitHub (pinned to 75dd419e61)
Solutions
- Make instructions.ts default-export a plain string: `export default 'You are a helpful assistant.'`
- If you need rich behavior, default-export a function that returns a string, system message, or array of them (sync or async), and verify the return value with the same shape rules.
- Add the missing `default` keyword if you exported a named constant (`export default instructions` instead of `export const instructions`).
- Log/inspect the default export at runtime (`import mod from './instructions.ts'; console.log(describeInstructionsExport(mod))`) to see what shape the resolver actually received.
Example fix
// before (agents/support/instructions.ts)
export const instructions = { instructions: 'You are support.' };
// after
export default 'You are support.'; Defensive patterns
Strategy: validation
Validate before calling
import mod from './agents/support/instructions.ts';
function isUsableInstructions(v: unknown): boolean {
const isSystemMessage = (x: unknown): x is { role: string; content: string } =>
!!x && typeof x === 'object' && 'role' in x && 'content' in x;
if (typeof v === 'string' || isSystemMessage(v)) return true;
if (Array.isArray(v) && v.every(x => typeof x === 'string' || isSystemMessage(x))) return true;
if (typeof v === 'function') return true; // must return one of the above when called
return false;
}
if (!isUsableInstructions(mod)) throw new Error('instructions.ts default export shape invalid'); Type guard
function isSystemMessage(v: unknown): v is { role: string; content: string } {
return typeof v === 'object' && v !== null && 'role' in v && 'content' in v && typeof (v as any).content === 'string';
} Try / catch
try {
agent = await resolveAgentFromFs('support');
} catch (e) {
if (e instanceof MastraError && e.id === 'AGENT_FS_ROUTING_INSTRUCTIONS_INVALID') {
console.error('Fix agents/support/instructions.ts:', e.detail?.received);
} else throw e;
} Prevention
- Always `export default` from instructions.ts, never a named export
- Keep the default export a plain string unless you specifically need dynamic behavior
- Add a unit test that imports every instructions.ts and asserts the exported shape
- If using a function export, test that its return value is a string/system message/array
When it happens
Trigger: Creating agents/<name>/instructions.ts with `export default { instructions: '...' }` (nested object), `export default undefined`, a class instance, a Promise, or a function returning an unsupported value; forgetting the `default` keyword entirely so the module's default export is undefined; exporting a named constant instead of default-exporting it.
Common situations: Migrating from an older format where instructions lived in config.ts to the dedicated instructions.ts file; copy-pasting instructions into a wrapper object; TypeScript compile of the file failing so the import yields undefined; authors exporting `async function` that resolves to undefined instead of returning a string/system message.
Related errors
- AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION
- AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED
- Okta domain is required. Provide it in the options or set OK
- Okta API token is required for RBAC. Provide it in the optio
- Supabase URL and anon key are required, please provide them
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f8d5fdac5ce787a4.
Report an issue: GitHub.