agalwood/Motrix · warning · FsTaskError
plugin.fs.rename_target_exists
plugin.fs.rename_target_exists
Error message
plugin.fs.rename_target_exists: ${newFilename} already exists in saveDir What it means
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.
Source
Thrown at src/core/plugin/capabilities/fs-task.ts:268
stream.on('end', () => resolve(hash.digest('hex')))
})
}
// -------------------------------------------------------------------------
// rename
// -------------------------------------------------------------------------
async rename(newFilename: string): Promise<void> {
// Throws FsSandboxError with code 'plugin.fs.invalid_basename' if not valid
assertBasename(newFilename)
const newPath = path.join(this.saveDir, newFilename)
// Check target doesn't already exist
try {
await fs.access(newPath)
// If we get here, file exists
throw new FsTaskError(
'plugin.fs.rename_target_exists',
`plugin.fs.rename_target_exists: ${newFilename} already exists in saveDir`
)
} catch (e: unknown) {
if (e instanceof FsTaskError) throw e
const err = e as NodeJS.ErrnoException
if (err.code !== 'ENOENT') throw e
// ENOENT = target doesn't exist, proceed
}
await fs.rename(this._filePath, newPath)
this._filePath = newPath
}
// -------------------------------------------------------------------------
// disposeAllReaders
// -------------------------------------------------------------------------
View on GitHub (pinned to 1a708ee577)
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.
Example fix
// before
await task.rename('result.json') // throws if a prior run left one
// after — unique name per run
await task.rename(`result-${crypto.randomUUID()}.json`) Defensive patterns
Strategy: validation
Validate before calling
async function uniqueName(saveDir: string, base: string): Promise<string> {
const ext = path.extname(base)
const stem = path.basename(base, ext)
for (let i = 0; ; i++) {
const candidate = `${stem}-${i}${ext}`
try { await fs.access(path.join(saveDir, candidate)); continue }
catch { return candidate }
}
} Type guard
function isRenameTargetExists(e: unknown): boolean {
return e instanceof Error && (e as FsTaskError).code === 'plugin.fs.rename_target_exists'
} Try / catch
try {
await task.rename(newFilename)
} catch (e) {
if (isRenameTargetExists(e)) { /* pick a unique name and retry */ }
else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Re-running a pipeline without cleaning the output dir; timestamp-based names that collide on rapid reruns; two workers picking the same derived name.
Related errors
- plugin.fs.overwrite_required
- plugin.fs.too_many_readers
- plugin.fs.chunk_too_large
- TaskNotFound
- taskId must be a string
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/700309328e188062.
Report an issue: GitHub.