{"record":{"id":"0c9df3d8c9303573","repo":"remix-run/react-router","slug":"the-provided-template-is-not-a-valid-local-directo","errorCode":null,"errorMessage":"The provided template is not a valid local directory or tarball.","messagePattern":"The provided template is not a valid local directory or tarball\\.","errorType":"exception","errorClass":"CopyTemplateError","httpStatus":null,"severity":"error","filePath":"packages/create-react-router/copy-template.ts","lineNumber":139,"sourceCode":") {\n  await copyTemplateFromRemoteTarball(url, destPath, options);\n}\n\nasync function copyTemplateFromLocalFilePath(\n  filePath: string,\n  destPath: string,\n): Promise<boolean> {\n  if (filePath.endsWith(\".tar.gz\") || filePath.endsWith(\".tgz\")) {\n    await extractLocalTarball(filePath, destPath);\n    return false;\n  }\n  if (fs.statSync(filePath).isDirectory()) {\n    // If our template is just a directory on disk, return true here, and we'll\n    // just copy directly from there instead of \"extracting\" to a temp\n    // directory first\n    return true;\n  }\n  throw new CopyTemplateError(\n    \"The provided template is not a valid local directory or tarball.\",\n  );\n}\n\nconst pipeline = promisify(stream.pipeline);\n\nasync function extractLocalTarball(\n  tarballPath: string,\n  destPath: string,\n): Promise<void> {\n  try {\n    await pipeline(\n      fs.createReadStream(tarballPath),\n      gunzip(),\n      tar.extract(destPath, { strip: 1 }),\n    );\n  } catch (error: unknown) {\n    throw new CopyTemplateError(","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/remix-run/react-router/blob/6beaca39526d5716c3c112ebb0782765baa5a9ce/packages/create-react-router/copy-template.ts#L121-L157","documentation":"copyTemplateFromLocalFilePath() throws this when the template resolved to an existing local path that is neither a .tar.gz/.tgz tarball nor a directory. The path existed (that is why it was routed to the local-file branch), but fs.statSync() shows it is a regular file with an unsupported extension — only directories and gzip tarballs are usable as local templates.","triggerScenarios":"Running with --template ./template.zip (zip is not supported); --template template.tar (plain tar, only .tar.gz/.tgz are recognized); --template pointing at any single regular file such as a .json, .md, or .tgz.txt.","commonSituations":"Downloading GitHub's 'Source code (zip)' archive instead of tar.gz; zipping a template directory with OS tools; renaming archives without converting their format.","solutions":["If the template is an archive, re-pack it as a gzip tarball: tar -czf template.tar.gz -C template-dir .","If it is a directory template, point --template at the directory itself","Unzip the file and pass the extracted directory as the template","Check the extension is exactly .tar.gz or .tgz"],"exampleFix":"# before\nnpx create-react-router my-app --template ./template.zip\n\n# after (repack as tar.gz)\ntar -czf template.tar.gz -C template .\nnpx create-react-router my-app --template ./template.tar.gz","handlingStrategy":"validation","validationCode":"import fs from \"node:fs\";\n\nfunction isUsableLocalTemplate(p: string): boolean {\n  if (!fs.existsSync(p)) return false;\n  if (p.endsWith(\".tar.gz\") || p.endsWith(\".tgz\")) return true;\n  try {\n    return fs.statSync(p).isDirectory();\n  } catch {\n    return false;\n  }\n}\n\nif (!isUsableLocalTemplate(templatePath)) {\n  throw new Error(\"Local template must be a directory or a .tar.gz/.tgz tarball\");\n}","typeGuard":"function isLocalTemplateCandidate(p: string): p is string {\n  return isUsableLocalTemplate(p);\n}","tryCatchPattern":"try {\n  await copyTemplate(templatePath, dest, { onError: (e) => { throw e; } });\n} catch (e) {\n  if (e instanceof CopyTemplateError && /not a valid local directory or tarball/.test(e.message)) {\n    console.error(`Repack ${templatePath} as .tar.gz or point at its extracted directory`);\n    process.exit(1);\n  }\n  throw e;\n}","preventionTips":["Standardize team templates on .tar.gz produced by tar -czf, not zip","Script template generation so the format is always directory or gzip tarball","Remember GitHub 'Source code (zip)' links are not usable directly"],"tags":["cli","template","filesystem","file-format"],"backgroundTag":"unsupported-file-format","analyzedSha":"6beaca39526d5716c3c112ebb0782765baa5a9ce","analyzedAt":"2026-08-18T18:04:14.938Z","contentChangedAt":"2026-08-18T18:04:14.938Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}