remix-run/react-router · error · CopyTemplateError
There was a problem fetching the file
Error message
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. What it means
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).
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
Example fix
# before GH_TOKEN=ghp_expiredtoken npx create-react-router my-app --token ghp_expiredtoken --template https://github.com/acme/private-tpl # after: fresh token verified first curl -s -H "Authorization: token $GH_TOKEN" https://api.github.com/user | grep login npx create-react-router my-app --token "$GH_TOKEN" --template https://github.com/acme/private-tpl
Defensive patterns
Strategy: validation
Validate before calling
async function tokenIsValid(token: string): Promise<boolean> {
const res = await fetch("https://api.github.com/user", {
headers: { Authorization: `token ${token}` },
});
return res.status === 200;
}
async function tokenCanReadRepo(token: string, owner: string, repo: string): Promise<boolean> {
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
headers: { Authorization: `token ${token}` },
});
return res.status === 200; // 404 means no access or missing repo
} Try / catch
try {
await createReactRouter([...args, "--token", token]);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (/--token`?is expired or invalid/.test(msg) || /--token` is expired/.test(msg)) {
console.error("Token rejected — regenerate it and re-verify with the /user endpoint.");
process.exit(1);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- There was a problem fetching the file from GitHub. The…
- There was a problem fetching the file from GitHub. No asset…
- There was a problem fetching the file
- No available port found
- No response body
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/da6a59afce1b5cdf.
Report an issue: GitHub.
Appendix: source
Thrown at packages/create-react-router/copy-template.ts:269
// If the release is "latest", the url won't match the download url
return info.tag === "latest"
? asset?.browser_download_url?.includes(info.asset)
: asset?.browser_download_url === tarballUrl;
})?.id;
if (assetId == null) {
throw new CopyTemplateError(
"There was a problem fetching the file from GitHub. No asset was " +
"found at that url. Please try again later.",
);
}
resourceUrl = `https://api.github.com/repos/${info.owner}/${info.name}/releases/assets/${assetId}`;
headers.Accept = "application/octet-stream";
}
let response = await fetch(resourceUrl, { headers });
if (!response.body || response.status !== 200) {
if (token) {
throw new CopyTemplateError(
`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.",
);
}
throw new CopyTemplateError(
`There was a problem fetching the file${
isGithubUrl ? " from GitHub" : ""
}. The request ` +
`responded with a ${response.status} status. Please try again later.`,
);
}
// file paths returned from GitHub are always unix style
if (filePath) {
filePath = filePath.split(path.sep).join(path.posix.sep);View on GitHub (pinned to 6beaca3952)