laurent22/joplin · error · Error
Extracting would overwrite
Error message
Extracting ${outPath} would overwrite What it means
Thrown during tar entry processing when the resolved output path for an entry already exists on disk. tarExtract treats extraction as non-destructive: it refuses to overwrite anything already present in the cwd target directory. The path is first sanitized through fsDriver.resolveRelativePathWithinDir(cwd, header.name) to prevent path traversal, then existence is checked.
Solutions
- Clean or use a fresh empty directory as cwd before extracting: await shim.fsDriver().removeAllDir(cwd); await shim.fsDriver().mkdir(cwd).
- If re-extraction is intentional, delete the specific colliding paths first.
- Inspect the tar's entry list (tar -tf on desktop) to find which entry name collides with outPath in the error message.
- Ensure the caller does not extract into the live resource directory without prior eviction.
Example fix
// before
tarExtract({ cwd: targetDir, file: archive });
// after — ensure a clean target
if (await shim.fsDriver().exists(targetDir)) {
await shim.fsDriver().removeAllDir(targetDir);
}
await shim.fsDriver().mkdir(targetDir);
tarExtract({ cwd: targetDir, file: archive }); Defensive patterns
Strategy: validation
Validate before calling
const fsDriver = shim.fsDriver();
// Ensure cwd is empty or pre-cleaned before extraction
const entries = await fsDriver.readDirStats(options.cwd);
if (entries.length > 0) {
await fsDriver.removeAllDir(options.cwd);
await fsDriver.mkdir(options.cwd);
}
await tarExtract(options); Type guard
function isCleanDir(stats) { return stats.length === 0; } Try / catch
try {
await tarExtract(options);
} catch (e) {
if (/Extracting .* would overwrite/.test(e.message)) {
const p = e.message.match(/Extracting (.*) would overwrite/)?.[1];
await shim.fsDriver().remove(p);
await tarExtract(options); // retry once
} else throw e;
} Prevention
- Extract into a freshly created empty directory.
- Never extract into the live resource directory without eviction.
- Keep the archive's entry list free of name collisions.
When it happens
Trigger: Extracting a tar into a cwd that already contains files/dirs with the same names; a previous interrupted extraction left partial files; extracting the same archive twice; the tar contains entries whose header.name collide with pre-existing user data in cwd.
Common situations: Re-running a backup restore into a non-empty directory; the restore target was not cleaned between attempts; a sync conflict deposited files with identical names; tar was built with absolute or duplicated entry names that collapse onto the same target.
Related errors
- Error! Destination already exists
- tarExtract: Source file does not exist
- Unsupported file system entity type
- Could not read directory
- Missing read-write access. It might be necessary to share…
AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12).
Data as JSON: /api/errors/fcc154b7195f7e94.
Report an issue: GitHub.
Appendix: source
Thrown at packages/app-mobile/utils/fs-driver/tarExtract.ts:30
const cwd = options.cwd;
// resolve doesn't correctly handle file:// or content:// URLs. Thus, we don't resolve relative
// to cwd if the source is a URL.
const isSourceUrl = options.file.match(/$[a-z]+:\/\//);
const filePath = isSourceUrl ? options.file : resolve(cwd, options.file);
const fsDriver = shim.fsDriver();
if (!(await fsDriver.exists(filePath))) {
throw new Error('tarExtract: Source file does not exist');
}
const extract = tarStreamExtract({ defaultEncoding: 'base64' });
extract.on('entry', async (header, stream, next) => {
const outPath = fsDriver.resolveRelativePathWithinDir(cwd, header.name);
if (await fsDriver.exists(outPath)) {
throw new Error(`Extracting ${outPath} would overwrite`);
}
// Allows moving to the next item after all data for this entry has been read
// **and** this data has been processed.
// See https://github.com/laurent22/joplin/issues/10285
const streamEndPromise = new Promise<void>((resolve) => {
stream.once('end', () => resolve());
});
if (header.type === 'directory') {
await fsDriver.mkdir(outPath);
} else if (header.type === 'file') {
const parentDir = dirname(outPath);
await fsDriver.mkdir(parentDir);
await fsDriver.appendBinaryReadableToFile(outPath, stream);
} else {
throw new Error(`Unsupported file system entity type: ${header.type}`);View on GitHub (pinned to 2654b33620)