{"record":{"id":"634e58dfa62109cd","repo":"sickn33/agentic-awesome-skills","slug":"http-response-status-response-statustext","errorCode":null,"errorMessage":"HTTP ${response.status}: ${response.statusText}","messagePattern":"HTTP (.+?): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"skills/expo-cicd-workflows/scripts/fetch.js","lineNumber":37,"sourceCode":"\n  // Make request, with conditional If-None-Match if we have an ETag.\n  // Cache-Control: max-age=0 overrides Node's default 'no-cache' to allow 304 responses.\n  const response = await fetch(url, {\n    headers: {\n      'Cache-Control': 'max-age=0',\n      ...(cached?.etag && { 'If-None-Match': cached.etag }),\n    },\n  });\n\n  if (response.status === 304 && cached) {\n    // Refresh expiration and return cached data\n    const entry = { ...cached, expires: getExpires(response.headers) };\n    await saveCacheEntry(cacheFile, entry);\n    return cached.data;\n  }\n\n  if (!response.ok) {\n    throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n  }\n\n  const etag = response.headers.get('etag');\n  const data = await response.text();\n  const expires = getExpires(response.headers);\n\n  await saveCacheEntry(cacheFile, { url, etag, expires, data });\n\n  return data;\n}\n\nfunction hashUrl(url) {\n  return createHash('sha256').update(url).digest('hex').slice(0, 16);\n}\n\nasync function loadCacheEntry(cacheFile) {\n  try {\n    return JSON.parse(await readFile(cacheFile, 'utf-8'));","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/sickn33/agentic-awesome-skills/blob/58d857988fcfac6986206bca2b2fe223aa437e4b/skills/expo-cicd-workflows/scripts/fetch.js#L19-L55","documentation":"fetchCached wraps Node's global fetch with an ETag/disk cache under scripts/.cache; after a non-304 response with response.ok false it throws a plain Error carrying the HTTP status and statusText. It surfaces upstream failures (404, 403, 5xx) from the remote endpoints the expo-cicd-workflows scripts fetch.","triggerScenarios":"Calling fetchCached(url) where the server returns 404 (deleted or moved workflow template URL), 403 (GitHub API rate limit without a token), or 5xx (service outage). Cache hits and 304 responses never throw.","commonSituations":"Expo SDK workflow URLs that changed between versions; unauthenticated GitHub API rate limits when polling many template refs; transient CI-provider 5xx during builds; stale hardcoded URLs.","solutions":["Read the status in the message: 404 means the URL no longer exists — update it to the current SDK version path","403 from api.github.com usually means rate limit — add an Authorization header or wait and retry","For 5xx/429, retry with backoff around fetchCached","Check for stale entries in skills/expo-cicd-workflows/scripts/.cache only if responses look wrong; errors are never cached"],"exampleFix":"// before\nconst yaml = await fetchCached(workflowUrl);\n\n// after\nasync function fetchWithRetry(url, tries = 3) {\n  for (let i = 0; i < tries; i++) {\n    try { return await fetchCached(url); }\n    catch (e) {\n      if (i === tries - 1 || !/^HTTP (5\\d\\d|429)/.test(e.message)) throw e;\n      await new Promise(r => setTimeout(r, 2000 * 2 ** i));\n    }\n  }\n}\nconst yaml = await fetchWithRetry(workflowUrl);","handlingStrategy":"retry","validationCode":"const u = new URL(target);\nif (!/^https?:$/.test(u.protocol)) throw new Error(`Unsupported protocol: ${u.protocol}`);","typeGuard":null,"tryCatchPattern":"for (let i = 0; i < 3; i++) {\n  try { return await fetchCached(url); }\n  catch (e) {\n    if (!/^HTTP /.test(e.message)) throw e;              // network error: fail fast\n    if (!/^HTTP (5\\d\\d|429)/.test(e.message) || i === 2) throw e; // other 4xx: permanent\n    await new Promise(r => setTimeout(r, 1000 * 2 ** i));\n  }\n}","preventionTips":["Keep template/asset URLs version-pinned; update on SDK upgrades","Authenticate GitHub API calls to raise rate limits","Treat 5xx/429 as retryable and 403/404 as permanent","Branch on the status code embedded in the message"],"tags":["network","http","fetch","expo"],"backgroundTag":"http-request-failed","analyzedSha":"58d857988fcfac6986206bca2b2fe223aa437e4b","analyzedAt":"2026-08-26T11:55:59.350Z","schemaVersion":2},"datasetVersion":"2026-08-26T14:46:13.012Z"}