can1357/oh-my-pi · error · Error
Failed to fetch marketplace catalog from ${source}: HTTP ${r
Error message
Failed to fetch marketplace catalog from ${source}: HTTP ${response.status} ${response.statusText} What it means
fetchMarketplace performs an HTTP GET of a URL-type marketplace source with a 60-second timeout and throws this when the response status is not OK (2xx). The message includes the URL, HTTP status code, and status text so the exact server rejection is visible.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/fetcher.ts:267
const resolved = path.resolve(expandHome(source));
const { catalogPath, content } = await readMarketplaceCatalog(resolved);
const catalog = parseMarketplaceCatalog(content, catalogPath);
return { catalog };
}
if (type === "github") {
const url = `https://github.com/${source}.git`;
return cloneAndReadCatalog(url, source, cacheDir);
}
if (type === "git") {
return cloneAndReadCatalog(source, source, cacheDir);
}
// type === "url"
const response = await fetch(source, { signal: AbortSignal.timeout(60_000) });
if (!response.ok) {
throw new Error(
`Failed to fetch marketplace catalog from ${source}: HTTP ${response.status} ${response.statusText}`,
);
}
const text = await response.text();
const catalog = parseMarketplaceCatalog(text, source);
const catalogDir = path.join(cacheDir, catalog.name);
await Bun.write(path.join(catalogDir, "marketplace.json"), text);
return { catalog };
}
// ── cloneAndReadCatalog ───────────────────────────────────────────────
/**
* Clone a git repository and read its marketplace catalog.
*
* Clones to a temporary directory and reads the catalog. The caller isView on GitHub (pinned to 9690622007)
Solutions
- Open the URL in a browser or with `curl -I` and confirm it returns 200 with JSON; fix the URL (use the raw content URL for GitHub-hosted catalogs).
- If the resource requires authentication, use a source type that supports credentials (e.g. git source with configured auth) instead of a plain URL.
- If the catalog moved, update the source or remove and re-add the marketplace with the new URL; retry later for transient 5xx errors.
Example fix
// before: HTML page URL
await fetchMarketplace("https://github.com/org/repo/blob/main/marketplace.json", cacheDir);
// after: raw content URL
await fetchMarketplace("https://raw.githubusercontent.com/org/repo/main/marketplace.json", cacheDir); Defensive patterns
Strategy: retry
Validate before calling
const res = await fetch(url, { method: "HEAD" });
if (!res.ok) throw new Error(`Catalog URL unreachable: HTTP ${res.status}`); Try / catch
try {
const catalog = await fetchMarketplace(url, cacheDir);
} catch (err) {
if ((err as Error).message.includes("HTTP ")) {
const status = Number((err as Error).message.match(/HTTP (\d+)/)?.[1]);
if (status >= 500) { /* retry with backoff */ }
else { /* fix URL / auth — do not retry 4xx */ }
} else throw err;
} Prevention
- Use raw-content URLs for hosted catalogs (raw.githubusercontent.com), not HTML pages.
- Check the URL returns 200 with curl or a browser before registering it.
- For authenticated resources, prefer a git source with configured credentials.
- Distinguish 4xx (fix the request) from 5xx (retry later).
When it happens
Trigger: fetchMarketplace("https://...") where the server returns 404 (wrong URL), 403 (private repo/forbidden), 500 (server error), or any other non-2xx status.
Common situations: A typo in the raw catalog URL; pointing at an HTML page instead of the raw JSON (e.g. a GitHub blob page instead of raw.githubusercontent.com); the catalog was moved/renamed upstream; a private URL without credentials; corporate proxy blocking the request.
Related errors
- HTTP error ${res.status} on ${endpoint}
- V2 remote compaction failed (${response.status} ${response.s
- AnthropicConnectionError
- AnthropicConnectionTimeoutError
- sso-role
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0bef312e3bc5ebb8.
Report an issue: GitHub.