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

  1. Verify the skill exists by checking the skills.sh page for that owner/repo/skillName
  2. Fix typos in owner, repo, or skillName in the request path/params
  3. Use encodeURIComponent-safe exact names (case sensitivity matters)
  4. 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

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


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