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

  1. Treat overwrite_required as success in create-if-absent flows (the file is already there).
  2. Pass `{overwrite:true}` when clobbering is intended.
  3. Use a unique path (UUID, hash) per write to avoid collisions entirely.
  4. 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

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


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/034c26cd66acb54a. Report an issue: GitHub.