remix-run/react-router · error · CopyTemplateError

There was a problem fetching the file from GitHub. The reque

Error message

There was a problem fetching the file from GitHub. The request responded with a ${response.status} status. Please try again later.

What it means

Thrown inside downloadAndExtractTarball() when the GitHub Releases API endpoint (api.github.com/repos/:owner/:name/releases/latest or .../tags/:tag) responds with a status other than 200. This branch runs only for URLs detected as GitHub release asset URLs (containing /releases/download/). A non-200 status typically means the tag/release does not exist (404), the repo is private/inaccessible (404/401), or you have been rate-limited (403).

Source

Thrown at packages/create-react-router/copy-template.ts:231

  let isGithubUrl = new URL(tarballUrl).host.endsWith("github.com");
  if (token && isGithubUrl) {
    headers.Authorization = `token ${token}`;
  }
  if (isGithubReleaseAssetUrl(tarballUrl)) {
    // We can download the asset via the GitHub api, but first we need to look
    // up the asset id
    let info = getGithubReleaseAssetInfo(tarballUrl);
    headers.Accept = "application/vnd.github.v3+json";

    let releaseUrl =
      info.tag === "latest"
        ? `https://api.github.com/repos/${info.owner}/${info.name}/releases/latest`
        : `https://api.github.com/repos/${info.owner}/${info.name}/releases/tags/${info.tag}`;

    let response = await fetch(releaseUrl, { headers });

    if (response.status !== 200) {
      throw new CopyTemplateError(
        "There was a problem fetching the file from GitHub. The request " +
          `responded with a ${response.status} status. Please try again later.`,
      );
    }

    let body = (await response.json()) as { assets: GitHubApiReleaseAsset[] };
    if (
      !body ||
      typeof body !== "object" ||
      !body.assets ||
      !Array.isArray(body.assets)
    ) {
      throw new CopyTemplateError(
        "There was a problem fetching the file from GitHub. No asset was " +
          "found at that url. Please try again later.",
      );
    }

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Open the URL in a browser to confirm the release and asset exist; if 404, find the correct tag.
  2. For private repos or to raise rate limits, generate a GitHub personal access token and pass --token <PAT>.
  3. If rate-limited, wait for the limit window to reset (check X-RateLimit-Reset header) or authenticate.
  4. Verify the owner/repo/tag spelling in the --template URL exactly matches the GitHub UI.

Example fix

// before
create-react-router my-app --template https://github.com/acme/templates/releases/download/v0.1.0/app.tar.gz
// after (release was retagged, and use a token for private repo)
create-react-router my-app --token $GITHUB_TOKEN --template https://github.com/acme/templates/releases/download/v0.2.0/app.tar.gz
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check the release exists and you can reach the API
async function releaseReachable(owner: string, repo: string, tag: string, token?: string) {
  const url = tag === 'latest'
    ? `https://api.github.com/repos/${owner}/${repo}/releases/latest`
    : `https://api.github.com/repos/${owner}/${repo}/releases/tags/${tag}`;
  const h: HeadersInit = { Accept: 'application/vnd.github.v3+json' };
  if (token) h.Authorization = `token ${token}`;
  const r = await fetch(url, { headers: h });
  if (r.status === 403) console.warn('rate-limited or forbidden');
  return r.status === 200;
}

Try / catch

try { await copyTemplate(url, dest, opts); }
catch (e) {
  if (e instanceof CopyTemplateError && /responded with a 40(3|4) status/.test(e.message)) {
    // back off and retry up to N times with exponential delay (rate limit / transient)
  } else throw e;
}

Prevention

When it happens

Trigger: Passing --template https://github.com/:owner/:repo/releases/download/:tag/template.tar.gz where :tag does not exist; the release was deleted or made draft after publishing the URL; the repository is private and no --token was supplied; GitHub API rate limit exceeded (403 with remaining: 0).

Common situations: CI hits the unauthenticated 60 req/hour GitHub rate limit; the release tag was renamed (e.g. v1.0 -> v1.0.0); a private fork whose release is not accessible; typoing the owner or repo segment in the URL.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/08df4818d07d6ad9. Report an issue: GitHub.