{"record":{"id":"efc87afd778ddf70","repo":"heygen-com/hyperframes","slug":"http-res-status-fetching-url","errorCode":null,"errorMessage":"HTTP ${res.status} fetching ${url}","messagePattern":"HTTP (.+?) fetching (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/skillsManifest.ts","lineNumber":647,"sourceCode":"/**\n * Narrow an untrusted JSON payload to a SkillsManifest, or throw a clear error.\n * Guards against a CDN serving an error page (or a malformed manifest) as 200 —\n * without this, a bad shape surfaces later as a cryptic crash in diffSkills.\n */\nfunction asSkillsManifest(data: unknown, sourceLabel: string): SkillsManifest {\n  const m = data as Partial<SkillsManifest> | null;\n  if (!m || typeof m !== \"object\" || typeof m.skills !== \"object\" || m.skills === null) {\n    throw new Error(`Malformed skills manifest from ${sourceLabel}`);\n  }\n  return m as SkillsManifest;\n}\n\nasync function fetchManifest(url: string): Promise<SkillsManifest> {\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n  try {\n    const res = await fetch(url, { signal: controller.signal, headers: { Connection: \"close\" } });\n    if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);\n    return asSkillsManifest(await res.json(), url);\n  } finally {\n    clearTimeout(timeout);\n  }\n}\n\n/**\n * Resolve main's live HEAD sha via `git ls-remote`. GitHub's branch-raw CDN\n * (raw.githubusercontent.com/<owner>/<repo>/main/...) can serve stale content\n * for minutes after a push; a SHA-pinned raw URL is immediately consistent.\n * Returns null when git/network is unavailable so callers fall back to main.\n */\nasync function remoteHeadSha(repoSlug: string): Promise<string | null> {\n  try {\n    const { stdout } = await execFileAsync(\n      \"git\",\n      [\"ls-remote\", `https://github.com/${repoSlug}.git`, \"refs/heads/main\"],\n      { timeout: FETCH_TIMEOUT_MS, env: { ...process.env, GIT_TERMINAL_PROMPT: \"0\" } },","sourceCodeStart":629,"sourceCodeEnd":665,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/utils/skillsManifest.ts#L629-L665","documentation":"Thrown by fetchManifest when the HTTP response from a remote skills manifest URL has a non-OK status code. Unlike the malformed-manifest guard, this fires before JSON parsing — the server itself rejected the request. The URL and status code are included in the message.","triggerScenarios":"The manifest URL returns 404 (wrong path or repo), 403 (private repo without access), 5xx (server error), or any other non-2xx status. The fetch includes an AbortController with FETCH_TIMEOUT_MS, so a timeout triggers an AbortError (a different error), not this.","commonSituations":"Specifying a wrong owner/repo slug; the repo was renamed or made private; GitHub rate-limiting returns 403; the manifest path changed in a newer version of the skills repo; temporary CDN outage.","solutions":["Check the status code in the error — 404 means wrong path/repo, 403 means private or rate-limited, 5xx means server error.","Verify the URL is correct by opening it in a browser.","If rate-limited by GitHub, wait a few minutes and retry, or use a local manifest source.","Fall back to the default repo by omitting the custom source."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function fetchManifestWithRetry(url: string, maxRetries = 3): Promise<SkillsManifest> {\n  for (let i = 0; i < maxRetries; i++) {\n    try {\n      return await fetchManifest(url);\n    } catch (err) {\n      if (err instanceof Error && err.includes(\"HTTP 5\") && i < maxRetries - 1) {\n        await new Promise((r) => setTimeout(r, 1000 * (i + 1)));\n        continue;\n      }\n      throw err;\n    }\n  }\n  throw new Error(`Failed after ${maxRetries} retries`);\n}","preventionTips":["Verify the manifest URL is correct and accessible before relying on it.","For GitHub raw URLs, use the default repo slug to avoid path errors.","Have a local manifest fallback for when the remote is unreachable."],"tags":["skills","manifest","network","http"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}