{"record":{"id":"dca88459677f7bff","repo":"gatsbyjs/gatsby","slug":"fetcherror-could-not-fetch-pathorurl-from-o","errorCode":null,"errorMessage":"{\"fetchError\":\"Could not fetch ${pathOrUrl} from official recipes\"}","messagePattern":"\\{\"fetchError\":\"Could not fetch \\$\\{pathOrUrl\\} from official recipes\"\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"deprecated-packages/gatsby-recipes/src/resolve-recipe.js","lineNumber":28,"sourceCode":"\n  return false\n}\n\nexport default async function resolveRecipe(pathOrUrl, projectRoot) {\n  let recipePath\n  if (isUrl(pathOrUrl)) {\n    const res = await fetch(pathOrUrl)\n    const src = await res.text()\n    return src\n  }\n  if (isRelative(pathOrUrl)) {\n    recipePath = path.join(projectRoot, pathOrUrl)\n  } else {\n    const url = `https://unpkg.com/gatsby-recipes/recipes/${pathOrUrl}`\n    const res = await fetch(url.endsWith(`.mdx`) ? url : url + `.mdx`)\n\n    if (res.status !== 200) {\n      throw new Error(\n        JSON.stringify({\n          fetchError: `Could not fetch ${pathOrUrl} from official recipes`,\n        })\n      )\n    }\n\n    const src = await res.text()\n    return src\n  }\n  if (recipePath.slice(-4) !== `.mdx`) {\n    recipePath += `.mdx`\n  }\n\n  const src = await fs.readFile(recipePath, `utf8`)\n  return src\n}\n","sourceCodeStart":10,"sourceCodeEnd":45,"githubUrl":"https://github.com/gatsbyjs/gatsby/blob/8b06340921ffdf23125a365b9c9923690cb62ce6/deprecated-packages/gatsby-recipes/src/resolve-recipe.js#L10-L45","documentation":"Thrown by `resolveRecipe` (resolve-recipe.js:28) when fetching an official recipe from `https://unpkg.com/gatsby-recipes/recipes/<name>.mdx` returns a non-200 HTTP status. The error is JSON-stringified (`{fetchError: ...}`) so the caller can parse and display it. Only the official-recipe branch (not URL, not relative path) performs this check.","triggerScenarios":"Passing a recipe name that does not exist on unpkg; offline or firewalled environment blocking unpkg.com; unpkg CDN outage; typo in the recipe name; using a recipe that exists only in a newer/older published gatsby-recipes package.","commonSituations":"Corporate proxy blocking unpkg; typo like `gatsby recipes add-typescriptt`; running `gatsby recipes` with an old globally installed CLI pointing at recipes removed from the current package; transient unpkg downtime.","solutions":["Check the recipe name spelling against the official recipes list.","Pass a full URL (`isUrl`) or a relative path to a local `.mdx` file instead of relying on unpkg.","Verify network connectivity to unpkg.com (curl the URL).","Retry — unpkg outages are usually transient."],"exampleFix":"// before\nresolveRecipe(`add-typescriptt`, projectRoot)\n\n// after\nresolveRecipe(`adding-typescript`, projectRoot)\n// or local file:\nresolveRecipe(`./recipes/my-recipe.mdx`, projectRoot)","handlingStrategy":"retry","validationCode":"async function canFetchRecipe(name) {\n  const url = `https://unpkg.com/gatsby-recipes/recipes/${name}.mdx`\n  const res = await fetch(url)\n  return res.status === 200\n}","typeGuard":"function isFetchErrorMessage(msg) {\n  try { return JSON.parse(msg).fetchError != null } catch { return false }\n}","tryCatchPattern":"try {\n  await resolveRecipe(name, root)\n} catch (e) {\n  if (isFetchErrorMessage(e.message)) { /* fall back to local file or retry */ }\n  else throw e\n}","preventionTips":["Prefer local recipe paths in air-gapped environments.","Validate recipe names against the official catalog before fetching.","Implement retry/backoff for transient unpkg failures."],"tags":["network","recipes","fetch","unpkg","deprecated"],"backgroundTag":null,"analyzedSha":"8b06340921ffdf23125a365b9c9923690cb62ce6","analyzedAt":"2026-08-13T02:36:21.405Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}