ErrLookup › Background articles › "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it
"already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it
"File already exists" errors — surfaced as FileAlreadyExistsException, AlreadyExistsException, io::ErrorKind::AlreadyExists, EEXIST, or a plain "already exists" message — happen when a program tries to create, copy, write, or move a file onto a path that is already occupied and was not told it may overwrite. Developers meet this family when re-running jobs against stale output, sharing directories or store locations between two writers, reinstalling tools over existing files, or relying on create-once semantics that hit an existing file. This page explains the layers that produce it, the common causes (stale leftovers, reruns, races, default overwrite=false), and the fixes that hold across libraries.
Distilled from 92 documented records across 37 repositories.
Background
This family lives at the boundary between an application's intent ('put content at this path') and the filesystem's refusal to let an existing entry be silently replaced. At the lowest level it is the POSIX O_CREAT|O_EXCL / EEXIST contract: exclusive creation fails if the target exists. High-level APIs reinterpret that contract in two directions. Hadoop's FileSystem and FileContext stack, and its object-store connectors (OBS, CosN, GCS, TOS), formalize it as an explicit overwrite flag: fs.create(path) defaults overwrite to false, so any create over an existing file throws FileAlreadyExistsException, and creating over a directory throws even with overwrite=true. Deno's fs.cp does the opposite by default — it skips — and only errors with EEXIST / ERR_FS_CP_EEXIST when you set errorOnExist with force:false. Node's copyFile with COPYFILE_EXCL, Rust's create_new, and shells' noclobber (used by mastra's sandbox writeFile with overwrite:false) all turn the OS guarantee into a language-level error.
Above the raw contract, many libraries layer policy on top of the same primitive. Installers and CLIs refuse to clobber user data: GitButler's macOS installer renames an existing ~/.local/bin/but to a .backup.<timestamp> file before symlinking, tauri's signer generate demands --force to replace a keypair, deno install -g aborts on an existing binary unless -f is passed, and october's media manager blocks uploads that would overwrite unless the user both posts force_overwrite and holds the media delete permission. Others use the error as a feature: mastra treats FileExistsError as create-once/lock semantics, CodeWhale's immutable artifact store accepts a re-write only if the bytes are identical and fails with AlreadyExists otherwise, and Hadoop's GCS connector uses generation-based preconditions so two concurrent creators race safely and the loser gets the exception.
From the caller's side the message usually arrives with little context beyond the path — the useful question is always 'why does that path already have something on it?' The dominant answers in this family are stale leftovers from a previous crashed or interrupted run (HDFS rbw temp files after a DataNode kill -9, half-finished SiYuan imports leaving assets behind, re-running a job against an uncleaned output dir), two writers pointed at the same location (two JobHistoryServers sharing a recovery store, two processes racing for the same name), and names that collide after normalization (claw-code sanitizing 'Code Review' and 'code-review' to the same file, sanitized artifact ids colliding, timestamp names generated twice within one second).
Details vary enough that you must read your library's contract. Whether overwrite is opt-in (Hadoop), opt-out (mastra), or forced via a CLI flag (tauri, deno install) is library-specific; whether a directory at the target is a hard error even with overwrite (Hadoop object connectors) or a different message entirely (viewfs mount-table errors like '/ is not a file. The directory / already exist at: ...') differs per implementation; and whether an identical-bytes rewrite is idempotent (CodeWhale) or always an error (remotion's codemods, which never overwrite scaffolded files) is a deliberate design choice, not a bug. One behavior is consistent across the family: none of these errors mean the filesystem is broken — they mean something is already at the path, and the software refuses to destroy it without an explicit decision.
Common causes
- Re-running jobs or commands against stale output. A previous run already wrote the destination file, and create/copy/install is invoked again with overwrite disabled or without a --force flag. This is the dominant trigger across Hadoop connectors, FileUtil.copy, deno install, tauri signer generate, and the HDFS local scratch examples.
- Leftovers from a crashed or interrupted run. A DataNode killed mid-write leaves an rbw temp block file; a failed or cancelled SiYuan import leaves assets in the workspace; an aborted write leaves temp or lock files behind. The next attempt finds the path occupied by data nobody cleaned up.
- Two writers sharing one location. Two JobHistoryServers pointed at the same recovery store URI, two processes racing for the same filename, or concurrent creators hitting the same GCS object (the loser gets the exception via the generation precondition). Shared directories and shared store URIs are the recurring culprit.
- Overwrite defaults to off. Many APIs (fs.create(path), FileSystem.create helper overloads, copyFile with COPYFILE_EXCL, writeFile with overwrite:false) default to exclusive creation, so callers collide with existing files without ever asking to overwrite. The fix is passing the explicit overwrite flag.
- Name collisions after normalization. Different logical names map to the same physical path: claw-code sanitizes 'Code Review' and 'code-review' to one file, CodeWhale's sanitize_id_component maps 'a/b' and 'a_b' to the same artifact, and timestamp-based names collide when generated twice within one second.
- Target is a directory, not a file. Hadoop object connectors throw 'is a directory' even with overwrite=true, and viewfs mount-table internal dirs reject creation outright ('/ is not a file. The directory / already exist'). Rename variants fail when a directory source meets a file destination.
What usually fixes it
- Decide rerun semantics explicitly: pass overwrite=true (or the CLI --force / -f flag) when clobbering is safe, pre-delete the existing entry, or write to unique per-run paths (attempt id / timestamp / job id) and publish atomically. Never rely on API defaults you have not checked.
- Clean stale state before retrying: remove or archive leftover output files, scratch dirs, temp and lock files, and half-finished import assets named in the error. For HDFS, prefer proper block/lease recovery over hand-deleting in-progress files while the DataNode runs.
- Ensure single-writer ownership of shared locations: exactly one JHS per recovery store URI, one writer per file across failovers, and stop squatters that pre-create another writer's temp-name patterns in shared directories.
- Make names collision-proof: derive filenames from attempt/task ids or content hashes, avoid same-second timestamp names, and keep sanitized (lowercased, character-restricted) names distinct in your tooling.
- Respect type and namespace conflicts: create files at leaf paths, not on directories or mount-table internal dirs; check the destination's type with a status call before expensive operations and fail early with your own clearer message.
Documented occurrences
- ${tokenPath} already exists (apache/hadoop)
- A mount path(file/dir) already exist with the requested path: {} (apache/hadoop)
- Moving it to {} to preserve your existing file (gitbutlerapp/gitbutler)
- temporary path creation collided (pnpm/pnpm)
- {} already exists (apache/hadoop)
- File {f} already exists (apache/hadoop)
- Cannot create ${relativeToRoot(componentFilePath, project.rootDir)} because it already exists (remotion-dev/remotion)
- 350: global attachment [%s] already exists (siyuan-note/siyuan)
- Unable to write keypair (tauri-apps/tauri)
- {} already exists (apache/hadoop)
- Object %s already exists. (apache/hadoop)
- A mount path(file/dir) already exist with the requested path: <fullPath> (apache/hadoop)
- EEXIST: ${target} already exists — leaving it untouched. (rohitg00/agentmemory)
- {} already exists (apache/hadoop)
- ERR_FS_CP_EEXIST: Target already exists (denoland/deno)
- A media file already exists at this location, please upload using a different filename. (octobercms/october)
- ${keyPath} already exists (apache/hadoop)
- Failed to create temporary file for {}. File {} should not be present, but is. (apache/hadoop)
- {} is a directory (apache/hadoop)
- target already exists (jackwener/OpenCLI)
…and 72 more across the corpus — use search.
Honest provenance: generated on 2026-08-31 from AI-assisted analysis of the linked records. See how records are made.