{"record":{"id":"6d286593d636a4ae","repo":"badges/shields","slug":"unparseable-intermediate-json-response","errorCode":null,"errorMessage":"unparseable intermediate json response","messagePattern":"unparseable intermediate json response","errorType":"exception","errorClass":"InvalidResponse","httpStatus":424,"severity":"error","filePath":"core/base-service/resource-cache.js","lineNumber":51,"sourceCode":"  options = {},\n  requestFetcher = fetch,\n}) {\n  const timestamp = Date.now()\n  const cached = resourceCache[url]\n  if (cached != null && timestamp - cached.timestamp < ttl) {\n    return cached.data\n  }\n\n  const { buffer } = await checkErrorResponse({})(\n    await requestFetcher(url, options),\n  )\n\n  let reqData\n  if (json) {\n    try {\n      reqData = JSON.parse(buffer)\n    } catch (e) {\n      throw new InvalidResponse({\n        prettyMessage: 'unparseable intermediate json response',\n        underlyingError: e,\n      })\n    }\n  } else {\n    reqData = buffer\n  }\n\n  const data = scraper(reqData)\n  resourceCache[url] = { timestamp, data }\n  return data\n}\n\nfunction clearResourceCache() {\n  resourceCache = Object.create(null)\n}\n\nexport { getCachedResource, clearResourceCache }","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/core/base-service/resource-cache.js#L33-L69","documentation":"getCachedResource in resource-cache.js fetches a resource and, when the json option is set, parses the cached buffer with JSON.parse. If parsing fails it throws InvalidResponse with prettyMessage 'unparseable intermediate json response' — an 'intermediate' resource is data fetched to compute further responses (versions, releases), not the final badge payload.","triggerScenarios":"JSON.parse(buffer) throws while reading a cached/fetched intermediate resource (e.g. getOfferedVersions, getPhpReleases) because the upstream endpoint returned non-JSON content or the cache holds corrupted data.","commonSituations":"Upstream metadata endpoint (releases/versions list) down and returning HTML, stale or corrupted cache entry written during an earlier partial response, provider API path changed.","solutions":["Clear the affected cache entry (and any local cache directory) so a fresh fetch occurs.","Curl the intermediate resource URL to confirm it returns valid JSON.","Check whether the upstream metadata endpoint moved or changed format.","Verify the fetchLimit didn't truncate the body mid-JSON.","Retry after a transient upstream outage; the cache will then store valid JSON."],"exampleFix":"// before (cached HTML from outage)\nreqData = JSON.parse('<html>503...</html>') // throws\n// after\ncache.clear(key); const reqData = JSON.parse(await refetchBuffer()) // valid JSON","handlingStrategy":"fallback","validationCode":"function safeParseJson(buffer) { try { return { ok: true, data: JSON.parse(buffer) } } catch (e) { return { ok: false } } }\nif (!safeParseJson(buffer).ok) refreshCacheAndRetry()","typeGuard":"function isParsedResource(v) { return typeof v === 'object' && v !== null }","tryCatchPattern":"try {\n  reqData = await getCachedResource({ url, json: true })\n} catch (err) {\n  if (err.name === 'InvalidResponse') {\n    cache.clear(key)\n    reqData = await getCachedResource({ url, json: true, skipCache: true })\n  } else throw err\n}","preventionTips":["Clear/purge cache entries when upstream outages are suspected.","Cap response size so truncated bodies don't get cached.","Monitor intermediate metadata endpoints for format changes.","Validate cached content shape before reuse."],"tags":["json","cache","parsing","upstream"],"backgroundTag":"unparseable-json-response","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}