{"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/1fd704a7dabcbe3ae09d7387b460e6acaba30ec1/packages/create-react-router/copy-template.ts#L251-L287","documentation":"Thrown when the final fetch of the resolved resourceUrl (release asset API URL or the original tarball URL) returns a non-200 status or no body, AND a --token was supplied. Because a token is present, the message specifically suggests the token is expired or invalid rather than a generic transient failure. isGithubUrl (host ends with github.com) controls whether 'from GitHub' is inserted.","triggerScenarios":"The supplied --token is expired, revoked, or lacks scope for the asset; asset requires a paid/private scope; token has read:packages but not repo access; rate limit per-token exceeded (403); the asset URL was valid but was just deleted (404).","commonSituations":"Long-lived CI token rotated by an org policy; fine-grained PAT without the 'Contents: read' permission; token belongs to an account that lost access to the repo; copy-paste error introduced whitespace into the token.","solutions":["Generate a fresh token (classic PAT with 'repo' or a fine-grained PAT with 'Contents: read' on the repo) and pass --token again.","Confirm the token works against the API: curl -H 'Authorization: token <TOKEN>' https://api.github.com/...","Verify the token has not been revoked and the owning account still has access to the repo/release.","If you intentionally have no auth needs, drop --token to get the no-token variant of the message and debug as anonymous."],"exampleFix":"// before\ncreate-react-router my-app --token ghp_OLDTOKEN --template https://github.com/acme/private/releases/download/v1/app.tar.gz\n// after -- fresh token with Contents: read\ncreate-react-router my-app --token $(cat ~/.config/crr-token) --template https://github.com/acme/private/releases/download/v1/app.tar.gz","handlingStrategy":"validation","validationCode":"// Confirm a token is live and has access before scaffolding\nasync function tokenCanReadRepo(token: string, owner: string, repo: string) {\n  const r = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {\n    headers: { Authorization: `token ${token}`, Accept: 'application/vnd.github.v3+json' },\n  });\n  return r.status === 200;\n}","typeGuard":null,"tryCatchPattern":"try { await copyTemplate(url, dest, { ...opts, token }); }\ncatch (e) {\n  if (e instanceof CopyTemplateError && /--token/.test(e.message)) {\n    // rotate token, verify scopes, then retry once\n  } else throw e;\n}","preventionTips":["Rotate long-lived tokens and prefer fine-grained PATs scoped to the repo.","Read tokens from a secret manager / env, never hardcode.","Verify scope includes 'Contents: read' for the target repo.","Test the token with a curl against api.github.com before the build."],"tags":["network","github-api","auth","token","release","create-react-router"],"backgroundTag":null,"analyzedSha":"1fd704a7dabcbe3ae09d7387b460e6acaba30ec1","analyzedAt":"2026-08-12T13:54:57.804Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}