mastra-ai/mastra · error
MastraCode requires at least one mode
Error message
MastraCode requires at least one mode
What it means
createMastraCodeAgentController() derives defaultModeId by finding a mode with metadata.default === true, then the 'build' mode, then modes[0]. If the modes array is empty, all lookups yield undefined and the controller throws, since MastraCode cannot operate without at least one agent mode.
Source
Thrown at mastracode/sdk/src/index.ts:1059
? undefined
: selectPreferredOMPack(startupAccess, activeProviderId)?.modelId;
const effectiveObserverModel = resolveOmRoleModel(globalSettings, 'observer', builtinOmPacks) || preferredOmModel;
const effectiveReflectorModel = resolveOmRoleModel(globalSettings, 'reflector', builtinOmPacks) || preferredOmModel;
const effectiveObservationThreshold = globalSettings.models.omObservationThreshold ?? undefined;
const effectiveReflectionThreshold = globalSettings.models.omReflectionThreshold ?? undefined;
const effectiveCavemanObservations = globalSettings.models.omCavemanObservations ?? undefined;
const effectiveObserveAttachments = globalSettings.models.omObserveAttachments ?? 'auto';
const modes = addPluginToolsToModeAllowlists(
applyEffectiveDefaultsToModes(config?.modes ? config.modes : defaultModes, effectiveDefaults),
Object.keys(pluginTools),
);
const defaultModeId =
modes.find(mode => mode.metadata?.default === true)?.id ??
modes.find(mode => mode.id === 'build')?.id ??
modes[0]?.id;
if (!defaultModeId) {
throw new Error('MastraCode requires at least one mode');
}
// Map subagent types to mode models: explore→fast, plan→plan, execute→build
// const subagentModeMap: Record<string, string> = { explore: 'fast', plan: 'plan', execute: 'build' };
// Subagents inherit workspace tools from the parent agent's workspace automatically.
// Apply disabledTools filter to both default and custom subagents.
// const subagents = [];
// Build initial state with global preferences. OM knobs are skipped when the
// host persists memory settings elsewhere (`disableSettingsOmSeed`) so the
// machine-local settings.json never leaks into server sessions.
const globalInitialState: Partial<MastraCodeState> = {};
if (!config?.disableSettingsOmSeed) {
if (effectiveObserverModel) {
globalInitialState.observerModelId = effectiveObserverModel;
}
if (effectiveReflectorModel) {
globalInitialState.reflectorModelId = effectiveReflectorModel;View on GitHub (pinned to 75dd419e61)
Solutions
- Ensure at least one mode is registered, ideally one with metadata: { default: true } or id: 'build'.
- Log the resolved modes array before creating the controller to find what filtered them all out.
- If building modes dynamically, fall back to including the built-in 'build' mode when the list is empty.
Example fix
// before const modes = enabledModes.filter(m => flags[m.id]); // can be [] // after const resolved = enabledModes.filter(m => flags[m.id]); const modes = resolved.length > 0 ? resolved : [buildMode];
Defensive patterns
Strategy: validation
Validate before calling
const hasDefault = modes.some(m => m.metadata?.default === true || m.id === 'build');
if (!Array.isArray(modes) || modes.length === 0) {
throw new Error('modes config resolved to an empty list; register at least one mode');
} Type guard
function hasAtLeastOneMode(ms: unknown): ms is NonEmptyArray<MastraCodeMode> {
return Array.isArray(ms) && ms.length > 0;
} Try / catch
try {
controller = await createMastraCodeAgentController({ ...cfg, modes });
} catch (err) {
if (err instanceof Error && err.message.includes('requires at least one mode')) {
controller = await createMastraCodeAgentController({ ...cfg, modes: [defaultBuildMode] });
} else { throw err; }
} Prevention
- Always register a mode with metadata.default: true (or id 'build') as a baseline.
- Log the modes array after dynamic filtering to catch empty results early.
- Make mode filters additive rather than subtractive so a bad flag can't remove all modes.
When it happens
Trigger: Constructing the controller with a modes configuration that resolves to an empty array — e.g. all modes filtered out by feature flags/disabledTools config, a custom modes loader returning [], or misconfigured modes config paths yielding no entries.
Common situations: Custom setups that override modes but forget to include a default/'build' mode; config-driven mode gating that excludes everything in a minimal environment; typos in mode registration that silently skip all modes.
Related errors
- Google client ID is required. Provide it in the options or s
- Path must include :agentId to route to the correct agent or
- LinearIntegration is missing required config: ${missing.join
- FACTORY_CREDENTIAL_ENCRYPTION_PREVIOUS_KEYS values must be b
- DATABASE_URL is required outside local development and tests
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/eec4b8e3762228c4.
Report an issue: GitHub.