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

  1. Verify the token: curl -H "Authorization: token $TOKEN" https://api.github.com/user must return 200
  2. Regenerate the token and confirm the same account can view the template repo in a browser
  3. For fine-grained PATs, grant read/content access to the specific repository
  4. 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

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


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)