{"record":{"id":"700309328e188062","repo":"agalwood/Motrix","slug":"plugin-fs-rename-target-exists","errorCode":"plugin.fs.rename_target_exists","errorMessage":"plugin.fs.rename_target_exists: ${newFilename} already exists in saveDir","messagePattern":"plugin\\.fs\\.rename_target_exists: (.+?) already exists in saveDir","errorType":"exception","errorClass":"FsTaskError","httpStatus":null,"severity":"warning","filePath":"src/core/plugin/capabilities/fs-task.ts","lineNumber":268,"sourceCode":"      stream.on('end', () => resolve(hash.digest('hex')))\n    })\n  }\n\n  // -------------------------------------------------------------------------\n  // rename\n  // -------------------------------------------------------------------------\n\n  async rename(newFilename: string): Promise<void> {\n    // Throws FsSandboxError with code 'plugin.fs.invalid_basename' if not valid\n    assertBasename(newFilename)\n\n    const newPath = path.join(this.saveDir, newFilename)\n\n    // Check target doesn't already exist\n    try {\n      await fs.access(newPath)\n      // If we get here, file exists\n      throw new FsTaskError(\n        'plugin.fs.rename_target_exists',\n        `plugin.fs.rename_target_exists: ${newFilename} already exists in saveDir`\n      )\n    } catch (e: unknown) {\n      if (e instanceof FsTaskError) throw e\n      const err = e as NodeJS.ErrnoException\n      if (err.code !== 'ENOENT') throw e\n      // ENOENT = target doesn't exist, proceed\n    }\n\n    await fs.rename(this._filePath, newPath)\n    this._filePath = newPath\n  }\n\n  // -------------------------------------------------------------------------\n  // disposeAllReaders\n  // -------------------------------------------------------------------------\n","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/fs-task.ts#L250-L286","documentation":"Thrown by FsTask.rename(newFilename) when `fs.access(newPath)` succeeds — i.e. a file with the proposed name already exists in saveDir. The rename is intentionally non-clobbering to prevent accidental overwrites; the existence check runs before `fs.rename`. Code is `plugin.fs.rename_target_exists`. Note assertBasename() runs first, so an invalid name throws invalid_basename instead.","triggerScenarios":"Calling `task.rename('out.txt')` when `saveDir/out.txt` already exists; rename collides with a previous run's output; concurrent tasks writing to the same directory with predictable names.","commonSituations":"Re-running a pipeline without cleaning the output dir; timestamp-based names that collide on rapid reruns; two workers picking the same derived name.","solutions":["Generate a unique name (append a UUID, hash, or high-resolution timestamp) before renaming.","Check existence yourself and either delete-then-rename or pick an alternate name.","Clean the output directory at the start of the run if clobbering is acceptable.","Use a per-run subdirectory under saveDir to isolate outputs."],"exampleFix":"// before\nawait task.rename('result.json') // throws if a prior run left one\n\n// after — unique name per run\nawait task.rename(`result-${crypto.randomUUID()}.json`)","handlingStrategy":"validation","validationCode":"async function uniqueName(saveDir: string, base: string): Promise<string> {\n  const ext = path.extname(base)\n  const stem = path.basename(base, ext)\n  for (let i = 0; ; i++) {\n    const candidate = `${stem}-${i}${ext}`\n    try { await fs.access(path.join(saveDir, candidate)); continue }\n    catch { return candidate }\n  }\n}","typeGuard":"function isRenameTargetExists(e: unknown): boolean {\n  return e instanceof Error && (e as FsTaskError).code === 'plugin.fs.rename_target_exists'\n}","tryCatchPattern":"try {\n  await task.rename(newFilename)\n} catch (e) {\n  if (isRenameTargetExists(e)) { /* pick a unique name and retry */ }\n  else throw e\n}","preventionTips":["Append a UUID/high-res timestamp to generated output names.","Clean the output dir at the start of each run if clobbering is acceptable.","Use per-run subdirectories to isolate concurrent outputs."],"tags":["fs","task","rename","collision","idempotency"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}