laurent22/joplin · error · Error

Extracting ${outPath} 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.

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)

Solutions

  1. Clean or use a fresh empty directory as cwd before extracting: await shim.fsDriver().removeAllDir(cwd); await shim.fsDriver().mkdir(cwd).
  2. If re-extraction is intentional, delete the specific colliding paths first.
  3. Inspect the tar's entry list (tar -tf on desktop) to find which entry name collides with outPath in the error message.
  4. 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

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


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/fcc154b7195f7e94. Report an issue: GitHub.