remix-run/react-router · error · CopyTemplateError

"${template}" is an invalid template. Run "create-react-rout

Error message

"${template}" is an invalid template. Run "create-react-router --help" to see supported template formats.

What it means

Thrown by copyTemplate() when the --template value matches none of the recognized formats: a local file path (file:// or existing path), GitHub owner/repo shorthand, a full github.com URL, or any other http(s) URL. The string is passed through isLocalFilePath, isGithubRepoShorthand, isValidGithubRepoUrl, and isUrl in order; if all return false, the value is rejected. The error message echoes the offending template and points to create-react-router --help.

Source

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

    if (isGithubRepoShorthand(template)) {
      log(`Using the template from the "${template}" repo`);
      await copyTemplateFromGithubRepoShorthand(template, destPath, options);
      return;
    }

    if (isValidGithubRepoUrl(template)) {
      log(`Using the template from "${template}"`);
      await copyTemplateFromGithubRepoUrl(template, destPath, options);
      return;
    }

    if (isUrl(template)) {
      log(`Using the template from "${template}"`);
      await copyTemplateFromGenericUrl(template, destPath, options);
      return;
    }

    throw new CopyTemplateError(
      `"${color.bold(template)}" is an invalid template. Run ${color.bold(
        "create-react-router --help",
      )} to see supported template formats.`,
    );
  } catch (error) {
    await options.onError(error);
  }
}

interface CopyTemplateOptions {
  debug?: boolean;
  token?: string;
  onError(error: unknown): any;
  log?(message: string): any;
}

function isLocalFilePath(input: string): boolean {
  try {

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Run create-react-router --help and copy a supported template format verbatim (owner/repo, https://github.com/owner/repo, https://host/file.tar.gz, ./local/dir).
  2. If using a local path, verify it exists: ls <path> before passing --template; fix the path or use an absolute path.
  3. For GitHub repos, use the HTTPS URL form https://github.com/:owner/:repo (optionally /tree/:branch/:dir) rather than ssh/git@ URLs.
  4. For non-GitHub hosts, point --template at a direct .tar.gz URL rather than the repo page.
  5. Omit --template entirely to use the default template (remix-run/react-router-templates default).

Example fix

// before
create-react-router my-app --template git@github.com:remix-run/react-router.git
// after
create-react-router my-app --template https://github.com/remix-run/react-router
Defensive patterns

Strategy: validation

Validate before calling

// Validate a --template value before invoking the CLI programmatically
import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';

function isUrl(s: string): boolean { try { new URL(s); return true; } catch { return false; } }
function isLocalPath(s: string): boolean {
  if (s.startsWith('file://')) return true;
  try { return fs.existsSync(path.isAbsolute(s) ? s : path.resolve(process.cwd(), s)); } catch { return false; }
}
function isGithubShorthand(s: string): boolean { return !isUrl(s) && /^[\w-]+\/[\w-.]+(\/[\w-.]+)*$/.test(s); }
function isValidGithubUrl(s: string): boolean {
  if (!isUrl(s)) return false;
  try { const u = new URL(s); const seg = u.pathname.slice(1).split('/');
    return u.protocol === 'https:' && u.hostname === 'github.com' && seg.length >= 2 && (seg.length > 2 ? seg[2] === 'tree' && seg.length >= 4 : true);
  } catch { return false; }
}
export function isValidTemplate(t: string): boolean {
  return isLocalPath(t) || isGithubShorthand(t) || isValidGithubUrl(t) || isUrl(t);
}
// if (!isValidTemplate(template)) fail fast with a friendlier message

Type guard

function isValidTemplate(t: unknown): t is string {
  if (typeof t !== 'string') return false;
  return isLocalPath(t) || isGithubShorthand(t) || isValidGithubUrl(t) || isUrl(t);
}

Prevention

When it happens

Trigger: Running create-react-router --template <x> where <x> is neither an existing path, nor a owner/repo shorthand (regex ^[\w-]+/[\w-.]+(/...)*$), nor an https://github.com/... URL, nor any other valid URL (isUrl uses URL parsing). Examples: a typo like 'remix-run/react-router-extra' with a disallowed char, an ssh git@ URL, an 'ftp://' URL, or a relative path that doesn't exist on disk.

Common situations: Passing an SSH clone URL (git@github.com:owner/repo.git) instead of HTTPS; passing a path that does not exist yet so isLocalFilePath's fs.existsSync returns false; using a GitLab/Bitbucket URL which is not a generic tarball URL; trailing slash or fragment that breaks the GitHub URL validator; copy-pasting a template name with a typo.

Related errors


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