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
- Retry the request after a short backoff (the upstream may be transiently failing).
- Check the upstream status in the message (e.g. 429 → wait, 5xx → outage) and inspect https://skills.sh availability.
- If rate limited (429), reduce request frequency or add caching of search results.
- 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
- Wrap registry calls in retry-with-backoff (upstream 5xx is usually transient).
- Cache search results to reduce upstream pressure.
- Watch for 429 in the message and back off accordingly.
- Have a fallback (local skills search) for registry outages.
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
- Failed to fetch from models.dev: ${response.statusText}
- Skills API error: ${response.status} ${response.statusText}
- Token exchange failed: ${error}
- Failed to fetch user info from Auth0
- Token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/7c0f8932297793f5.
Report an issue: GitHub.