{"record":{"id":"da6a59afce1b5cdf","repo":"remix-run/react-router","slug":"there-was-a-problem-fetching-the-file-isgithuburl","errorCode":null,"errorMessage":"There was a problem fetching the file${isGithubUrl ? \" from GitHub\" : \"\"}. The request responded with a ${response.status} status. Perhaps your `--token`is expired or invalid.","messagePattern":"There was a problem fetching the file(.+?)\\. The request responded with a (.+?) status\\. Perhaps your `--token`is expired or invalid\\.","errorType":"exception","errorClass":"CopyTemplateError","httpStatus":null,"severity":"error","filePath":"packages/create-react-router/copy-template.ts","lineNumber":269,"sourceCode":"      // If the release is \"latest\", the url won't match the download url\n      return info.tag === \"latest\"\n        ? asset?.browser_download_url?.includes(info.asset)\n        : asset?.browser_download_url === tarballUrl;\n    })?.id;\n    if (assetId == null) {\n      throw new CopyTemplateError(\n        \"There was a problem fetching the file from GitHub. No asset was \" +\n          \"found at that url. Please try again later.\",\n      );\n    }\n    resourceUrl = `https://api.github.com/repos/${info.owner}/${info.name}/releases/assets/${assetId}`;\n    headers.Accept = \"application/octet-stream\";\n  }\n  let response = await fetch(resourceUrl, { headers });\n\n  if (!response.body || response.status !== 200) {\n    if (token) {\n      throw new CopyTemplateError(\n        `There was a problem fetching the file${\n          isGithubUrl ? \" from GitHub\" : \"\"\n        }. The request ` +\n          `responded with a ${response.status} status. Perhaps your \\`--token\\`` +\n          \"is expired or invalid.\",\n      );\n    }\n    throw new CopyTemplateError(\n      `There was a problem fetching the file${\n        isGithubUrl ? \" from GitHub\" : \"\"\n      }. The request ` +\n        `responded with a ${response.status} status. Please try again later.`,\n    );\n  }\n\n  // file paths returned from GitHub are always unix style\n  if (filePath) {\n    filePath = filePath.split(path.sep).join(path.posix.sep);","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/create-react-router/copy-template.ts#L251-L287","documentation":"The final HTTP fetch of the tarball (codeload URL or release asset API URL) returned a non-200 status or an empty body while a --token was supplied, so the CLI suggests the token is expired or invalid. Typical statuses: 401 (bad credentials), 404 (token cannot see the private repo — GitHub answers 404 instead of 403), 403 (expired token or rate limit).","triggerScenarios":"Revoked or expired personal access token; fine-grained PAT without read access to the private template repo; token from a different account; token pasted with surrounding whitespace; authenticated rate limit exceeded.","commonSituations":"Company tokens rotated without updating CI secrets; classic PATs used where a fine-grained PAT scoped to the repo is required; long-lived local tokens expiring silently.","solutions":["Verify the token: curl -H \"Authorization: token $TOKEN\" https://api.github.com/user must return 200","Regenerate the token and confirm the same account can view the template repo in a browser","For fine-grained PATs, grant read/content access to the specific repository","Omit --token entirely if the template repo is public"],"exampleFix":"# before\nGH_TOKEN=ghp_expiredtoken npx create-react-router my-app --token ghp_expiredtoken --template https://github.com/acme/private-tpl\n\n# after: fresh token verified first\ncurl -s -H \"Authorization: token $GH_TOKEN\" https://api.github.com/user | grep login\nnpx create-react-router my-app --token \"$GH_TOKEN\" --template https://github.com/acme/private-tpl","handlingStrategy":"validation","validationCode":"async function tokenIsValid(token: string): Promise<boolean> {\n  const res = await fetch(\"https://api.github.com/user\", {\n    headers: { Authorization: `token ${token}` },\n  });\n  return res.status === 200;\n}\n\nasync function tokenCanReadRepo(token: string, owner: string, repo: string): Promise<boolean> {\n  const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {\n    headers: { Authorization: `token ${token}` },\n  });\n  return res.status === 200; // 404 means no access or missing repo\n}","typeGuard":null,"tryCatchPattern":"try {\n  await createReactRouter([...args, \"--token\", token]);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (/--token`?is expired or invalid/.test(msg) || /--token` is expired/.test(msg)) {\n    console.error(\"Token rejected — regenerate it and re-verify with the /user endpoint.\");\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Verify tokens with GET /user and GET /repos/:owner/:repo before any scaffold run","Prefer fine-grained PATs scoped to the specific template repos","Store tokens in CI secret managers with rotation reminders instead of long-lived local files"],"tags":["network","github-api","authentication","token"],"backgroundTag":"invalid-api-token","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}