mastra-ai/mastra · error · MastraError
AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED
AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED
Error message
Agent "${name}": subagent "${childId}" requires a non-empty 'description'. Set one in agents/${name}/subagents/${childId}/config.ts. What it means
mergeSubAgents assembles each filesystem subagent and calls getDescription(); a subagent used for delegation must carry a non-empty description because that text is what the parent agent's model uses to decide when to hand off. Empty, whitespace-only, or missing descriptions cause this USER error at assembly time.
Source
Thrown at packages/core/src/agent/fs-routing/index.ts:660
text: `Agent "${name}": duplicate subagent "${childId}" under agents/${name}/subagents/.`,
});
}
if (toolKeys.has(childId)) {
throw new MastraError({
id: 'AGENT_FS_ROUTING_SUBAGENT_NAME_COLLISION',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { agentName: name, subagentName: childId },
text: `Agent "${name}": subagent "${childId}" collides with a tool of the same name. Rename agents/${name}/subagents/${childId}/ or the tool.`,
});
}
const child = assembleAtDepth(childEntry, depth + 1, options);
const description = child.getDescription();
if (!description || description.trim() === '') {
throw new MastraError({
id: 'AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
details: { agentName: name, subagentName: childId },
text: `Agent "${name}": subagent "${childId}" requires a non-empty 'description'. Set one in agents/${name}/subagents/${childId}/config.ts.`,
});
}
if (configKeys.has(childId)) {
onWarn(
`Agent "${name}": subagent "${childId}" defined in both config.agents and subagents/; config.agents wins.`,
);
continue;
}
fromFs[childId] = child;
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Add a meaningful `description` to agents/<name>/subagents/<child>/config.ts explaining what the subagent does and when to use it.
- Trim-check the value: the description must not be empty or whitespace-only after trim().
- If the description comes from a shared constant/import, verify the imported value is actually populated at runtime.
Example fix
// before (agents/main/subagents/researcher/config.ts)
export const config = { name: 'researcher', description: '', /* ... */ };
// after
export const config = { name: 'researcher', description: 'Searches the web and summarizes findings for research questions.', /* ... */ }; Defensive patterns
Strategy: validation
Validate before calling
const configs = import.meta.glob('./agents/*/subagents/*/config.ts', { eager: true });
for (const [path, mod] of Object.entries(configs)) {
const desc = (mod as any).config?.description;
if (typeof desc !== 'string' || desc.trim() === '') {
throw new Error(`Missing non-empty description in ${path}`);
}
} Type guard
function hasNonEmptyDescription(c: unknown): c is { name: string; description: string } {
return typeof c === 'object' && c !== null && 'description' in c &&
typeof (c as any).description === 'string' && (c as any).description.trim() !== '';
} Try / catch
try {
buildAgentFromFs('main');
} catch (e) {
if (e instanceof MastraError && e.id === 'AGENT_FS_ROUTING_SUBAGENT_DESCRIPTION_REQUIRED') {
console.error('Set a description for subagent:', e.detail?.subagentName);
} else throw e;
} Prevention
- Include `description` in your subagent scaffold/template
- Write descriptions from the model's perspective: what it does and when the parent should delegate
- Add a lint/test that every subagent config passes a non-empty trimmed description check
- Avoid whitespace-only placeholder descriptions
When it happens
Trigger: agents/<name>/subagents/<child>/config.ts omitting the `description` field; setting `description: ''` or only whitespace (e.g. `' '`); constructing a subagent programmatically (via assembleAtDepth path) whose description getter returns empty.
Common situations: Scaffolding a new subagent quickly and skipping the description; templated configs where the placeholder string was deleted; refactors that moved description into a shared constant that resolved to an empty string.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- Cookie password must be at least 32 characters. Set WORKOS_C
- Factory rule version is required.
- ${label} must be an object.
- Factory rules must be an object.
- [QueueHealthStorage] thresholdsSeconds must be a non-empty a
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/10c7f53d8e7551ef.
Report an issue: GitHub.