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. Please try again later. What it means
The tarball download (codeload.github.com tarball, api.github.com tarball redirect, or generic URL) failed with a non-200 status and no token was supplied. Because no credentials were involved, this points at the resource itself or transient conditions: 404 for a nonexistent or private repo/branch, 403 from GitHub API rate limiting, or 5xx during a GitHub incident.
Solutions
- If the repo is private, pass --token with a PAT that can read it
- Verify the repo and branch exist by opening the URL in a browser
- Check rate limits: curl https://api.github.com/rate_limit
- Retry after a few minutes for transient failures or incidents
Example fix
# before: private repo, no token -> 404 npx create-react-router my-app --template https://github.com/acme/private-tpl/tree/main # after: supply a token with read access npx create-react-router my-app --token "$GH_TOKEN" \ --template https://github.com/acme/private-tpl/tree/main
Defensive patterns
Strategy: retry
Validate before calling
async function repoIsPubliclyFetchable(owner: string, repo: string, branch?: string) {
const res = await fetch(
`https://api.github.com/repos/${owner}/${repo}` + (branch ? `/branches/${branch}` : ""),
);
if (res.status === 404) {
throw new Error("Repo/branch missing or private — pass --token");
}
if (res.status === 403) {
throw new Error("Rate limited — export GITHUB_TOKEN or retry later");
}
return res.ok;
} Try / catch
async function scaffoldWithBackoff(args: string[], attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await createReactRouter(args);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
const retryable = /problem fetching the file/.test(msg) && !/404/.test(msg);
if (!retryable || i === attempts - 1) throw e;
await new Promise((r) => setTimeout(r, 2 ** i * 5_000));
}
}
} Prevention
- Export GITHUB_TOKEN in CI even for public template repos to avoid the 60 req/h anonymous quota
- Pass --token for any template repo that might be private
- Verify branch names when pinning /tree/:branch URLs
When it happens
Trigger: Scaffolding from a private repo without --token (404); a deleted or renamed branch in a /tree/:branch URL; unauthenticated GitHub API quota exhausted (60 requests/hour per IP); transient GitHub outage or network failure.
Common situations: Template repos moved or deleted; typos in branch names; CI runners on shared IPs exhausting the unauthenticated quota; flaky networks.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- There was a problem fetching the file from GitHub. The…
- No available port found
- There was a problem extracting the file from the provided…
- There was a problem fetching the file from GitHub. No asset…
- There was a problem fetching the file
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/55c4f6135230ca23.
Report an issue: GitHub.
Appendix: source
Thrown at packages/create-react-router/copy-template.ts:277
"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);
}
let filePathHasFiles = false;
try {
let input = new stream.PassThrough();
// Start reading stream into passthrough, don't await to avoid buffering
writeReadableStreamToWritable(response.body, input);View on GitHub (pinned to 6beaca3952)