mastra-ai/mastra · error · HTTPException

Skills API error: ${response.status} ${response.statusText}

Error message

Skills API error: ${response.status} ${response.statusText}

What it means

The skills.sh registry search proxies to SKILLS_SH_API_URL (/api/skills). If the upstream response is not ok, the handler wraps it into a 502 Bad Gateway including the upstream status and statusText. It signals an upstream registry problem, not an error in your request.

Source

Thrown at packages/server/src/server/handlers/workspace.ts:1190

  path: '/workspaces/:workspaceId/skills-sh/search',
  responseType: 'json',
  pathParamSchema: workspaceIdPathParams,
  queryParamSchema: skillsShSearchQuerySchema,
  responseSchema: skillsShSearchResponseSchema,
  summary: 'Search skills on skills.sh',
  description: 'Proxies search requests to skills.sh API to avoid CORS issues',
  tags: ['Workspace', 'Skills'],
  handler: async ({ q, limit }) => {
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 10000);

      const url = `${SKILLS_SH_API_URL}/api/skills?query=${encodeURIComponent(q)}&pageSize=${limit}`;
      const response = await fetch(url, { signal: controller.signal });
      clearTimeout(timeoutId);

      if (!response.ok) {
        throw new HTTPException(502, {
          message: `Skills API error: ${response.status} ${response.statusText}`,
        });
      }

      const data = (await response.json()) as {
        skills: Array<{
          skillId: string;
          name: string;
          installs: number;
          source: string;
          owner: string;
          repo: string;
          githubUrl: string;
          displayName: string;
        }>;
        total: number;
        page: number;
        pageSize: number;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Retry the request after a short backoff (the upstream may be transiently failing).
  2. Check the upstream status in the message (e.g. 429 → wait, 5xx → outage) and inspect https://skills.sh availability.
  3. If rate limited (429), reduce request frequency or add caching of search results.
  4. Verify no proxy/firewall is altering the response between the server and skills.sh.

Example fix

// before
const res = await fetch('/workspaces/ws1/skills/registry/search?query=pdf');
// after
try {
  const res = await fetch('/workspaces/ws1/skills/registry/search?query=pdf');
} catch (e) {
  await new Promise(r => setTimeout(r, 1000)); // backoff then retry
}
Defensive patterns

Strategy: retry

Validate before calling

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10_000); // fail fast before the 502 surfaces downstream

Type guard

function isUpstreamError(e: unknown): e is { status: number; message: string } {
  return typeof e === 'object' && e !== null && 'status' in e && (e as any).status === 502;
}

Try / catch

try {
  return await client.searchSkillRegistry({ query, limit });
} catch (e) {
  if (isUpstreamError(e)) {
    await sleep(retryAfterFrom(e) ?? 1000);
    return await client.searchSkillRegistry({ query, limit }); // retry once with backoff
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the skills registry search route while skills.sh returns a non-2xx (429 rate limit, 500, 503 outage), or network middleware returning an error page status.

Common situations: skills.sh rate limiting your IP; temporary registry outage; corporate proxy intercepting with 403; DNS handled but upstream degraded.

Related errors


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