remix-run/react-router · error · CopyTemplateError
There was a problem extracting the file from the provided…
Error message
There was a problem extracting the file from the provided template. Template filepath: `${tarballPath}` Destination directory: `${destPath}` ${error} What it means
extractLocalTarball() streams the local .tar.gz through gunzip-maybe and tar-fs into the destination directory via stream.pipeline; this error wraps any failure in that pipeline. The original error text is appended to the message, which tells you whether it was a gzip error (file not actually gzip-compressed), a tar parse error (corrupt archive), or a filesystem error (permissions, missing destination).
Solutions
- Verify the file is really gzip: 'file template.tar.gz' should report 'gzip compressed data'
- Verify integrity: 'tar -tzf template.tar.gz' should list entries without errors
- Re-create the tarball from the source directory: tar -czf template.tar.gz -C template-dir .
- Check write permissions and free space on the destination volume
Example fix
# before: renamed zip fails mv template.zip template.tar.gz npx create-react-router my-app --template ./template.tar.gz # after: real gzip tarball tar -czf template.tar.gz -C template . npx create-react-router my-app --template ./template.tar.gz
Defensive patterns
Strategy: try-catch
Validate before calling
import { execSync } from "node:child_process";
function verifyLocalTarball(p: string): void {
// Lists entries; non-zero exit means corrupt or not gzip
execSync(`tar -tzf ${JSON.stringify(p)}`, { stdio: "pipe" });
} Try / catch
try {
await copyTemplate(tarballPath, dest, { onError: (e) => { throw e; } });
} catch (e) {
if (e instanceof CopyTemplateError && /problem extracting/.test(e.message)) {
// The original cause is appended to the message
const cause = /gzip/.test(e.message) ? "not gzip data"
: /tar/.test(e.message) ? "corrupt archive"
: /EACCES|permission/i.test(e.message) ? "destination not writable"
: "truncated tarball";
console.error(`Extraction failed (${cause}); re-create with tar -czf`);
process.exit(1);
}
throw e;
} Prevention
- Generate template tarballs with tar -czf template.tar.gz -C dir . in CI so format is guaranteed
- Run tar -tzf as a smoke check in the template publish pipeline
- Never rename archives to .tar.gz — convert them
When it happens
Trigger: A file named *.tar.gz that is actually a renamed zip or plain tar; a tarball truncated by an interrupted download; an unwritable or deleted destination directory; disk-full conditions while extracting.
Common situations: Manually renaming archives to .tar.gz without converting them; partial downloads; tarballs produced on Windows with non-gzip compression; restricted OS temp directories.
Related errors
- There was a problem extracting the file from the provided…
- " " is an invalid template. Run to see supported template…
- package.json does not exist in
- package.json are invalid
- The path " " was not found in this
AI-assisted analysis of remix-run/react-router@6beaca3952 (2026-08-18).
Data as JSON: /api/errors/afe56b50272aee00.
Report an issue: GitHub.
Appendix: source
Thrown at packages/create-react-router/copy-template.ts:157
throw new CopyTemplateError(
"The provided template is not a valid local directory or tarball.",
);
}
const pipeline = promisify(stream.pipeline);
async function extractLocalTarball(
tarballPath: string,
destPath: string,
): Promise<void> {
try {
await pipeline(
fs.createReadStream(tarballPath),
gunzip(),
tar.extract(destPath, { strip: 1 }),
);
} catch (error: unknown) {
throw new CopyTemplateError(
"There was a problem extracting the file from the provided template." +
` Template filepath: \`${tarballPath}\`` +
` Destination directory: \`${destPath}\`` +
` ${error}`,
);
}
}
interface TarballDownloadOptions {
debug?: boolean;
filePath?: string | null;
token?: string;
}
async function downloadAndExtractRepoTarball(
repo: RepoInfo,
destPath: string,
options: TarballDownloadOptions,View on GitHub (pinned to 6beaca3952)