mastra-ai/mastra · error · SkillInvocationError
skill_not_found
skill_not_found
Error message
skill_not_found
What it means
resolveSkillInvocation found the session, refreshed workspace skills, but skills.get(input.name) returned nothing or the skill has 'user-invocable': false. It throws SkillInvocationError('skill_not_found') with the skill name in the message.
Source
Thrown at mastracode/factory/src/skills/service.ts:71
input: { resourceId: string; scope?: SkillInvocationInput['scope']; prompt: string },
): Promise<{ session: SkillSession; message: string }> {
const session = (await controller.getSessionByResource(input.resourceId, input.scope)) as SkillSession | undefined;
if (!session) throw new SkillInvocationError('session_not_found', 'Agent controller session not found.');
return { session, message: input.prompt };
}
export async function resolveSkillInvocation(
controller: Pick<AgentController<MastraCodeState>, 'getSessionByResource'>,
input: SkillInvocationInput,
): Promise<{ session: SkillSession; skillName: string; message: string }> {
const session = (await controller.getSessionByResource(input.resourceId, input.scope)) as SkillSession | undefined;
if (!session) throw new SkillInvocationError('session_not_found', 'Agent controller session not found.');
const skills = session.getWorkspace().skills;
await skills?.maybeRefresh();
const skill = await skills?.get(input.name);
if (!skill || skill['user-invocable'] === false) {
throw new SkillInvocationError('skill_not_found', `Skill not found: ${input.name}.`);
}
const args = input.arguments?.trim();
const content = `${formatSkillActivation(skill)}${args ? `\n\nARGUMENTS: ${args}` : ''}`.trim();
return {
session,
skillName: skill.name,
message: `<skill name="${skill.name}">\n${escapeSkillBoundary(content)}\n</skill>`,
};
}
export async function dispatchSkillInvocation(
controller: Pick<AgentController<MastraCodeState>, 'getSessionByResource'>,
input: SkillInvocationInput,
): Promise<{ skillName: string; message: string }> {
const resolved = await resolveSkillInvocation(controller, input);
await resolved.session.sendMessage({ content: resolved.message });
return { skillName: resolved.skillName, message: resolved.message };View on GitHub (pinned to 75dd419e61)
Solutions
- Check the skill name matches the skills directory/frontmatter exactly
- Ensure the skill frontmatter does not set 'user-invocable': false
- Call skills.maybeRefresh() or reload the workspace so newly added skills are visible
- List available skills from session.getWorkspace().skills to confirm the name
Example fix
// before
await resolveSkillInvocation(controller, { resourceId, name: 'Deploy-Skill' });
// after
const skills = session.getWorkspace().skills;
if (skills && !(await skills.get('deploy-skill'))) throw new Error('skill not installed in workspace');
await resolveSkillInvocation(controller, { resourceId, name: 'deploy-skill' }); Defensive patterns
Strategy: validation
Validate before calling
const skills = session.getWorkspace().skills;
await skills?.maybeRefresh();
const skill = await skills?.get(name);
if (!skill || skill['user-invocable'] === false) {
throw new Error(`Skill "${name}" missing or not user-invocable in this workspace`);
} Type guard
function isInvocableSkill(s: { 'user-invocable'?: boolean } | undefined): boolean {
return s != null && s['user-invocable'] !== false;
} Try / catch
try {
await resolveSkillInvocation(controller, input);
} catch (e) {
if (e instanceof SkillInvocationError && e.code === 'skill_not_found') {
const available = await session.getWorkspace().skills?.list?.() ?? [];
throw new Error(`Unknown skill "${input.name}". Available: ${available.join(', ')}`);
}
throw e;
} Prevention
- Refresh the skills workspace after installing new skills
- Match skill names exactly as in the directory/frontmatter
- Check frontmatter 'user-invocable' before exposing the skill to users
- Surface a skill list to callers instead of free-form names
When it happens
Trigger: Invoking a skill whose name doesn't exist in the session workspace's skills directory, a typo in input.name, or invoking a skill marked 'user-invocable': false in its frontmatter.
Common situations: Skill added after the session's workspace snapshot (refresh pending or not persisted); skill name mismatch (directory name vs frontmatter name); skill intentionally restricted to agent-only invocation.
Related errors
- Skill not found: ${invocation.skillName}.
- Workspace with id ${id} not found
- Skill "${identifier}" not found
- Workspace not found
- Could not find skill "${skillName}" in ${owner}/${repo}.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/9fdeecf46b377322.
Report an issue: GitHub.