mastra-ai/mastra · error
Mode "${modeRecord.id}" cannot set both "tools" and "additio
Error message
Mode "${modeRecord.id}" cannot set both "tools" and "additionalTools" - choose replace OR augment What it means
A mode may either replace the controller's tool set (tools) or augment it (additionalTools), but not both — the semantics would be ambiguous. validateModes throws at AgentController construction when a single mode sets both properties, forcing an explicit choose-one configuration.
Source
Thrown at packages/core/src/agent-controller/agent-controller.ts:73
* (e.g. `("a\0b", "c")` vs `("a", "b\0c")`).
*/
function sessionRegistryKey(resourceId: string, scope?: string): string {
return JSON.stringify([resourceId, scope ?? null]);
}
function validateModes(modes: AgentControllerMode[]): void {
const modeIds = new Set<string>();
for (const mode of modes) {
if (modeIds.has(mode.id)) {
throw new Error(`Duplicate mode id "${mode.id}" found when creating the AgentController`);
}
modeIds.add(mode.id);
const modeRecord = mode as unknown as { id: string; tools?: unknown; additionalTools?: unknown };
if (modeRecord.tools && modeRecord.additionalTools) {
throw new Error(
`Mode "${modeRecord.id}" cannot set both "tools" and "additionalTools" - choose replace OR augment`,
);
}
}
for (const mode of modes) {
if (mode.transitionsTo === mode.id) {
throw new Error(`Mode "${mode.id}" transitionsTo cannot reference itself`);
}
if (mode.transitionsTo && !modeIds.has(mode.transitionsTo)) {
throw new Error(`Mode "${mode.id}" transitionsTo references unknown mode "${mode.transitionsTo}"`);
}
}
}
/**
* Build a user-facing message for a non-success stream finish reason.
*View on GitHub (pinned to 75dd419e61)
Solutions
- Remove one of the two properties — move the base tools into additionalTools if you want augmentation
- Split into two modes if you genuinely need both replace and augment behavior
- Ensure config-merge logic does not combine tools and additionalTools into one mode
Example fix
// before
{ id: 'chat', tools: { read: readTool }, additionalTools: { write: writeTool } }
// after
{ id: 'chat', additionalTools: { read: readTool, write: writeTool } } Defensive patterns
Strategy: validation
Validate before calling
function assertNotBothTools(modes: { id: string; tools?: unknown; additionalTools?: unknown }[]): void {
for (const m of modes) {
if (m.tools && m.additionalTools) throw new Error(`Mode "${m.id}" sets both tools and additionalTools`);
}
}
assertNotBothTools(config.modes); Try / catch
try {
new AgentController(config);
} catch (e) {
if ((e as Error).message.includes('both "tools" and "additionalTools"')) {
// merge the offending mode's tools into additionalTools and retry
}
} Prevention
- Pick one tool-configuration style per mode (replace OR augment)
- Ensure config-merge helpers don't combine both fields
- Document the mutually-exclusive constraint in mode templates
When it happens
Trigger: Defining an AgentControllerMode with both a non-empty tools object and a non-empty additionalTools object; typically from merging two partial mode configs (one specifying tools, the other additionalTools) into the same mode.
Common situations: Combining a base-mode template (with tools) with a per-deployment override (with additionalTools); copy-paste edits adding extra tools without realizing tools was already set; framework defaults that pre-populate tools.
Related errors
- list-available-agents requires a Mastra context.
- list-available-tools requires a Mastra context.
- Duplicate mode id "${mode.id}" found when creating the Agent
- Mode "${mode.id}" transitionsTo cannot reference itself
- Mode "${mode.id}" transitionsTo references unknown mode "${m
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/0622bcee789e5fc6.
Report an issue: GitHub.