mastra-ai/mastra · error · HTTPException
Could not find skill "${skillName}" for ${owner}/${repo}
Error message
Could not find skill "${skillName}" for ${owner}/${repo} What it means
previewSkillsSh proxies the skills.sh API to preview a skill's content before it's installed. When the upstream skills.sh API responds 404 — meaning no skill exists at owner/repo/skillName — the route translates that into its own HTTPException 404. The library throws this to distinguish 'skill not found' from a generic upstream failure.
Source
Thrown at packages/server/src/server/handlers/skills-sh-shared.ts:227
export async function previewSkillsSh({
owner,
repo,
skillName,
}: {
owner: string;
repo: string;
skillName: string;
}): Promise<{ content: string }> {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), PREVIEW_TIMEOUT_MS);
try {
const url = `${SKILLS_SH_API_URL}/api/skills/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/${encodeURIComponent(skillName)}/content`;
const response = await fetch(url, { signal: controller.signal });
if (!response.ok) {
if (response.status === 404) {
throw new HTTPException(404, {
message: `Could not find skill "${skillName}" for ${owner}/${repo}`,
});
}
throw new HTTPException(502, {
message: `Skills API error: ${response.status} ${response.statusText}`,
});
}
const data = (await response.json()) as { instructions?: string; raw?: string };
const content = data.instructions || data.raw || '';
if (!content) {
throw new HTTPException(404, {
message: `No content available for skill "${skillName}"`,
});
}
return { content };View on GitHub (pinned to 75dd419e61)
Solutions
- Verify the skill exists by checking the skills.sh page for that owner/repo/skillName
- Fix typos in owner, repo, or skillName in the request path/params
- Use encodeURIComponent-safe exact names (case sensitivity matters)
- Handle 404 in the client UI with a 'skill not found' message instead of retrying
Example fix
// before
preview({ owner: 'acme', repo: 'utils', skillName: 'code-review' })
// after (verify name first, then handle 404)
const res = await fetch('/api/registry/preview?owner=acme&repo=utils&skillName=code-reviewer');
if (res.status === 404) showNotFound(); Defensive patterns
Strategy: try-catch
Validate before calling
const exists = await fetch(`https://skills.sh/api/skills/${owner}/${repo}/${skillName}/content`, { method: 'HEAD' }).then(r => r.status !== 404).catch(() => false);
if (!exists) throw new Error(`Skill ${skillName} not found on skills.sh`); Type guard
function isNotFoundResponse(e: unknown): e is { status: 404 } {
return typeof e === 'object' && e !== null && 'status' in e && (e as any).status === 404;
} Try / catch
try {
const preview = await api.previewSkill(owner, repo, skillName);
} catch (e) {
if (isNotFoundResponse(e)) showNotFound(owner, repo, skillName);
else throw e;
} Prevention
- Validate skill names against the skills.sh registry before previewing
- Copy owner/repo/skillName directly from the skills.sh URL to avoid typos
- Treat 404 as a terminal state — do not retry
When it happens
Trigger: Calling the registry preview route (BUILDER_REGISTRY_PREVIEW_ROUTE) with an owner/repo/skillName triple that doesn't exist on skills.sh; the upstream GET /api/skills/{owner}/{repo}/{skillName}/content returns status 404.
Common situations: Typo in skillName, owner, or repo; skill renamed or deleted upstream; previewing a private/unlisted skill that skills.sh doesn't expose; stale bookmark/URL pointing to a removed skill.
Related errors
- Model "${modelId}" is not available. Available models: ${ids
- ACP connection is not initialized
- Model "${this.options.model}" is not available. Available mo
- ClaudeSDKAgent resumeData must include either sessionId or c
- ClaudeSDKAgent resumeData.sessionId must be a string.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/269b02981f2d09c7.
Report an issue: GitHub.