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

  1. Add a meaningful `description` to agents/<name>/subagents/<child>/config.ts explaining what the subagent does and when to use it.
  2. Trim-check the value: the description must not be empty or whitespace-only after trim().
  3. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/10c7f53d8e7551ef. Report an issue: GitHub.