{"record":{"id":"ce87984790352e5b","repo":"gatsbyjs/gatsby","slug":"remote-file-node-is-null","errorCode":null,"errorMessage":"Remote file node is null","messagePattern":"Remote file node is null","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/gatsby-transformer-screenshot/src/gatsby-node.js","lineNumber":159,"sourceCode":"      expires = new Date(2999, 1, 1).getTime()\n    } else {\n      const screenshotResponse = await axios.post(\n        pluginOptions.screenshotEndpoint,\n        { url }\n      )\n\n      fileNode = await createRemoteFileNode({\n        url: screenshotResponse.data.url,\n        cache,\n        createNode,\n        createNodeId,\n        getCache,\n        parentNodeId,\n      })\n      expires = screenshotResponse.data.expires\n\n      if (!fileNode) {\n        throw new Error(`Remote file node is null`, screenshotResponse.data.url)\n      }\n    }\n\n    const screenshotNode = {\n      id: createNodeId(`${parent} >>> Screenshot`),\n      url,\n      expires,\n      parent,\n      children: [],\n      internal: {\n        type: `Screenshot`,\n      },\n      screenshotFile___NODE: fileNode.id,\n      usingPlaceholder: USE_PLACEHOLDER_IMAGE,\n    }\n\n    screenshotNode.internal.contentDigest = createContentDigest(screenshotNode)\n","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/packages/gatsby-transformer-screenshot/src/gatsby-node.js#L141-L177","documentation":"Thrown in gatsby-transformer-screenshot's gatsby-node.js after calling createRemoteFileNode with a screenshot URL. createRemoteFileNode is expected to return a file node object; if it returns null or undefined, the screenshot was not successfully downloaded and turned into a Gatsby File node, so the build cannot proceed.","triggerScenarios":"createRemoteFileNode is called with the URL from the screenshot service response, but returns falsy. This can happen when the remote download fails silently, the URL is unreachable from the build environment, or there is a network/timeout issue during 'gatsby build'.","commonSituations":"Build environment has no outbound internet access (e.g. corporate proxy, restricted CI), the screenshot service Lambda returned a URL that has expired or is not yet available, DNS resolution fails, or the remote server returns a non-200 status that createRemoteFileNode swallows.","solutions":["Verify the screenshot URL from screenshotResponse.data.url is reachable from the build machine: `curl -I <url>`.","Check that the screenshot Lambda completed and uploaded the image to S3 before the build node queries it (race condition between putFile and getFile).","If behind a proxy, configure HTTP_PROXY/HTTPS_PROXY so createRemoteFileNode can reach the URL.","Retry the build after confirming network connectivity; add logging around the createRemoteFileNode call to inspect the response."],"exampleFix":"// before\nfileNode = await createRemoteFileNode({\n  url: screenshotResponse.data.url,\n  // ...\n})\nif (!fileNode) {\n  throw new Error(`Remote file node is null`, screenshotResponse.data.url)\n}\n\n// after — log and retry before failing\nfileNode = await createRemoteFileNode({ url, cache, createNode, createNodeId, getCache, parentNodeId })\nif (!fileNode) {\n  console.warn(`Screenshot not ready at ${url}, retrying once...`)\n  await new Promise(r => setTimeout(r, 5000))\n  fileNode = await createRemoteFileNode({ url, cache, createNode, createNodeId, getCache, parentNodeId })\n}\nif (!fileNode) throw new Error(`Remote file node is null for ${url}`)","handlingStrategy":"retry","validationCode":"// Validate URL reachability before passing to createRemoteFileNode\nconst http = require('http')\nconst https = require('https')\n\nfunction checkUrl(url) {\n  return new Promise(resolve => {\n    const mod = url.startsWith('https') ? https : http\n    mod.request(url, { method: 'HEAD' }, res => resolve(res.statusCode === 200))\n      .on('error', () => resolve(false))\n      .end()\n  })\n}","typeGuard":null,"tryCatchPattern":"// Retry with backoff before giving up\nasync function createFileNodeWithRetry(url, deps, retries = 3) {\n  for (let i = 0; i < retries; i++) {\n    const fileNode = await createRemoteFileNode({ url, ...deps })\n    if (fileNode) return fileNode\n    await new Promise(r => setTimeout(r, 2000 * (i + 1)))\n  }\n  throw new Error(`Remote file node is null after ${retries} retries for ${url}`)\n}","preventionTips":["Add retry logic with exponential backoff around createRemoteFileNode for flaky remote sources.","Log the screenshot URL and response status to diagnose intermittent failures.","Ensure the screenshot Lambda and build share a consistent S3 region.","Configure HTTP_PROXY if the build environment requires a proxy for outbound calls."],"tags":["remote-file","network","build-time","createremotefilenode","gatsby-transformer-screenshot"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}