mastra-ai/mastra · error · HTTPException
Skill "${skillName}" not found at ${skillPath}
Error message
Skill "${skillName}" not found at ${skillPath} What it means
HTTP 404 thrown when the skill directory cannot be `stat`-ed at the computed path. The handler first looks up the skill in the skills cache (only if its path is under the skills.sh prefix), otherwise falls back to buildSkillInstallPath; if neither location exists on the filesystem, it reports the skill as not found and includes the exact path checked.
Source
Thrown at packages/server/src/server/handlers/workspace.ts:1567
if (workspace.filesystem.readOnly) {
throw new HTTPException(403, { message: 'Workspace is read-only' });
}
// Validate skill name to prevent path traversal
const safeSkillName = assertSafeSkillName(skillName);
// Look up the skill's actual path from the cache (supports glob-discovered skills).
// Only use the discovered path if it's under the skills.sh directory to avoid
// accidentally deleting a locally-authored skill with the same name.
const allSkills = await workspace.skills?.list();
const matchingSkill = allSkills?.find(s => s.name === safeSkillName && s.path.includes(SKILLS_SH_PATH_PREFIX));
const skillPath = matchingSkill?.path ?? buildSkillInstallPath(workspace.filesystem, safeSkillName);
// Check if skill exists on filesystem
try {
await workspace.filesystem.stat(skillPath);
} catch {
throw new HTTPException(404, { message: `Skill "${skillName}" not found at ${skillPath}` });
}
// Delete the skill directory
await workspace.filesystem.rmdir(skillPath, { recursive: true });
// Surgically remove the skill from the cache
if (workspace.skills?.removeSkill) {
try {
await workspace.skills.removeSkill(skillPath);
} catch (cacheError) {
console.warn(
`[skills-sh] Failed to update cache after remove: ${cacheError instanceof Error ? cacheError.message : String(cacheError)}`,
);
}
}
return {
success: true,View on GitHub (pinned to 75dd419e61)
Solutions
- List the workspace skills first and confirm the exact skill name/path before removing.
- Correct the skillName spelling/casing to match the installed directory.
- If the skill is stale state (already deleted), treat HTTP 404 as idempotent success in your caller.
- If installed at a custom path, remove it via the generic filesystem API instead of the skills-sh remove endpoint.
Example fix
// before
await ws.skillsSh.remove({ skillName: 'PdfTools' }); // 404
// after
const skills = await ws.skills.list();
const target = skills.find(s => s.name.toLowerCase() === 'pdftools');
if (target) await ws.skillsSh.remove({ skillName: target.name }); Defensive patterns
Strategy: validation
Validate before calling
const skills = (await workspace.skills?.list()) ?? [];
const target = skills.find(s => s.name === skillName);
if (!target) throw new Error(`Skill "${skillName}" is not installed in workspace ${workspaceId}`); Type guard
function isInstalledSkill(skills: Array<{ name: string; path: string }>, name: string) {
return skills.find(s => s.name === name) ?? null;
} Try / catch
try {
await removeSkill(workspaceId, skillName);
} catch (e) {
if (isHttpException(e, 404) && e.message.includes('not found at')) {
return { removed: false, reason: 'already-absent' }; // treat as idempotent success
}
throw e;
} Prevention
- Always list installed skills and match exact names before removing.
- Treat 404 from remove as idempotent success to make retries safe.
- Don't hand-write skill paths; use the discovered path from skills.list().
When it happens
Trigger: POST /workspaces/:workspaceId/skills-sh/remove with a skillName that was never installed, was already removed, has a name differing in case/spelling from the installed directory, or was installed outside the skills.sh prefix and at a non-default path.
Common situations: Retrying a remove after a successful delete (double-click, replayed request); typos in skill name; skill installed manually under a custom directory so cache discovery misses it; workspace filesystem reset between install and remove.
Related errors
- Skill "${identifier}" not found
- Could not find skill "${skillName}" in ${owner}/${repo}.
- No workspace with skills configured
- Could not find skill "${skillName}" for ${owner}/${repo}
- Workspace not found
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/20ce47a80a97de47.
Report an issue: GitHub.