{"record":{"id":"0993b51ed031fa32","repo":"gatsbyjs/gatsby","slug":"image-downloading-failed-for-originalimg-pleas","errorCode":null,"errorMessage":"Image downloading failed for ${originalImg}, please check if the image still exists on contentful","messagePattern":"Image downloading failed for (.+?), please check if the image still exists on contentful","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/gatsby-remark-images-contentful/src/index.js","lineNumber":78,"sourceCode":"    const cacheKey = `remark-images-ctf-${node.url}-${optionsHash}`\n    const cachedRawHTML = await cache.get(cacheKey)\n\n    if (cachedRawHTML) {\n      return cachedRawHTML\n    }\n    const sharp = await getSharpInstance()\n    const metaReader = sharp()\n\n    // @todo to increase reliablility, this should use the asset downloading function from gatsby-source-contentful\n    let response\n    try {\n      response = await axios({\n        method: `GET`,\n        url: originalImg, // for some reason there is a './' prefix\n        responseType: `stream`,\n      })\n    } catch (err) {\n      reporter.panic(\n        `Image downloading failed for ${originalImg}, please check if the image still exists on contentful`,\n        err\n      )\n      return []\n    }\n\n    response.data.pipe(metaReader)\n\n    let metadata\n    try {\n      metadata = await metaReader.metadata()\n    } catch (error) {\n      console.log(error)\n      reporter.panic(\n        `The image \"${node.url}\" (with alt text: \"${node.alt}\") doesn't appear to be a supported image format.`,\n        error\n      )\n    }","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby-remark-images-contentful/src/index.js#L60-L96","documentation":"In gatsby-remark-images-contentful (index.js:71-83), the plugin downloads images from Contentful's CDN using axios GET with responseType 'stream'. If the HTTP request fails (network error, 404, 403, DNS failure, timeout), the catch block calls reporter.panic with the image URL and the axios error. The image URL is derived from the markdown AST node.url, with a 'https:' prefix prepended if the URL doesn't start with http/https. After downloading, the stream is piped to sharp for metadata extraction.","triggerScenarios":"A Contentful image asset was deleted or unpublished after being referenced in markdown. Network connectivity issues during build. Contentful CDN returns 404/403 for the asset URL. DNS resolution failure. Build running in an environment without internet access. Rate limiting from Contentful CDN.","commonSituations":"Contentful asset deleted but markdown still references it. Build in CI without network access or behind a firewall. Contentful space/environment mismatch where assets exist in one environment but not another. Stale build cache referencing old asset URLs after content migration.","solutions":["Verify the image URL from the error message is accessible: curl -I <url>","Check Contentful: ensure the asset is published and exists in the target environment","Remove or update the markdown reference to the deleted image","For CI environments: ensure network access to Contentful CDN (images.ctfassets.net)","If rate-limited, reduce parallel image processing or add retries"],"exampleFix":"// before: markdown references a deleted Contentful image\n![Alt text](//images.ctfassets.net/space/asset/deleted-image.png)\n\n// after: update to a valid asset or remove the reference\n![Alt text](//images.ctfassets.net/space/asset/existing-image.png)","handlingStrategy":"retry","validationCode":"// Pre-build: validate all Contentful image URLs in markdown are reachable\nconst axios = require('axios')\n\nasync function validateContentfulImages(urls) {\n  for (const url of urls) {\n    try {\n      await axios.head(url)\n    } catch (err) {\n      console.error(`Contentful image unreachable: ${url} — ${err.message}`)\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"// If you control the markdown processing, wrap image fetching with retry:\nasync function fetchWithRetry(url, retries = 3) {\n  for (let i = 0; i < retries; i++) {\n    try {\n      return await axios({ method: 'GET', url, responseType: 'stream' })\n    } catch (err) {\n      if (i === retries - 1) throw err\n      const delay = Math.pow(2, i) * 1000\n      await new Promise(r => setTimeout(r, delay))\n    }\n  }\n}","preventionTips":["Ensure Contentful assets are published and not deleted before building","Run image URL validation as a pre-build step in CI","Keep Contentful environment consistent between content editing and builds","For CI: ensure network access to images.ctfassets.net and configure timeouts","Consider using gatsby-source-contentful's asset downloading for better reliability"],"tags":["network","contentful","image-processing","cdn","runtime-error"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}