agalwood/Motrix · warning · FsStorageError
plugin.fs.overwrite_required
plugin.fs.overwrite_required
Error message
plugin.fs.overwrite_required: ${relPath} already exists What it means
Thrown by FsStorage.write() when `opts.overwrite === false` and the target path already exists (verified via fs.access before touching disk). The write API defaults overwrite to true; passing `{overwrite:false}` opts into a create-only semantic. Code is `plugin.fs.overwrite_required`.
Source
Thrown at src/core/plugin/capabilities/fs-storage.ts:154
// -------------------------------------------------------------------------
// write (atomic)
// -------------------------------------------------------------------------
async write(
relPath: string,
data: string | Uint8Array,
opts?: { overwrite?: boolean; encoding?: 'utf8' | 'binary' }
): Promise<void> {
const overwrite = opts?.overwrite ?? true
const target = await resolveInsideSandbox(this.root, relPath)
// Overwrite guard — check before touching disk
if (!overwrite) {
try {
await fs.access(target)
// File exists: reject
throw new FsStorageError(
'plugin.fs.overwrite_required',
`plugin.fs.overwrite_required: ${relPath} already exists`
)
} catch (e: unknown) {
if (e instanceof FsStorageError) throw e
const err = e as NodeJS.ErrnoException
if (err.code !== 'ENOENT') throw e
// ENOENT = target missing, proceed with write
}
}
// Ensure parent directory exists
await fs.mkdir(path.dirname(target), { recursive: true })
// Atomic write: tmp file inside sandbox, then rename
const tmpPath = await resolveInsideSandbox(
this.root,
`${relPath}.tmp-${randomUUID()}`View on GitHub (pinned to 1a708ee577)
Solutions
- Treat overwrite_required as success in create-if-absent flows (the file is already there).
- Pass `{overwrite:true}` when clobbering is intended.
- Use a unique path (UUID, hash) per write to avoid collisions entirely.
- For lockfile semantics, use this error to detect an existing claim and back off.
Example fix
// before
await storage.write('lock', pid, { overwrite: false }) // throws if held
// after — treat 'already held' as expected
try { await storage.write('lock', pid, { overwrite: false }) }
catch (e) { if (isFsCode(e, 'plugin.fs.overwrite_required')) return 'busy'; throw e } Defensive patterns
Strategy: try-catch
Validate before calling
async function createIfAbsent(storage: FsStorage, rel: string, data: Uint8Array | string): Promise<'created'|'exists'> {
try { await storage.write(rel, data, { overwrite: false }); return 'created' }
catch (e) { if ((e as FsStorageError).code === 'plugin.fs.overwrite_required') return 'exists'; throw e }
} Type guard
function isOverwriteRequired(e: unknown): boolean {
return e instanceof Error && (e as FsStorageError).code === 'plugin.fs.overwrite_required'
} Try / catch
try {
await storage.write(rel, data, { overwrite: false })
} catch (e) {
if (isOverwriteRequired(e)) { /* file already present — proceed or back off */ }
else throw e
} Prevention
- Use unique per-run names to avoid collisions entirely.
- Treat overwrite_required as success in create-if-absent flows.
- Pass {overwrite:true} only when clobbering is explicitly intended.
When it happens
Trigger: Calling `storage.write(relPath, data, { overwrite: false })` when relPath already holds a file. Common in create-if-absent flows, atomic lockfile creation, or idempotent seeding.
Common situations: Idempotent setup scripts that must not clobber; lockfile/claim-file patterns; retry logic that re-runs write without overwrite and finds the previous attempt succeeded; concurrent writers racing for the same path.
Related errors
- plugin.fs.not_found
- plugin.fs.not_a_file
- plugin.fs.rename_target_exists
- plugin.fs.path_too_long
- plugin.fs.path_outside_sandbox
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/034c26cd66acb54a.
Report an issue: GitHub.