jackwener/OpenCLI · error · Error

target already exists

Error message

target already exists

What it means

reserveAudioFile refuses to overwrite an existing file: before taking the exclusive (wx-flag) lock, it checks fs.existsSync(target) and throws Error('target already exists'). The catch re-wraps it as CommandExecutionError('MiniMax music cannot reserve output file <target>: target already exists'). The same check runs again after locking to detect races, in which case the message is 'target appeared during reservation'.

Solutions

  1. Wait at least one second and re-run so the ISO-timestamp filename differs
  2. Choose a different output directory or move/rename the existing file
  3. Delete the stale target file if it is from a failed earlier run: rm <target> (also remove <target>.lock if left behind)
  4. Wrap the call in a retry that regenerates with a new Date() to get a fresh stamp

Example fix

// before: second call in the same second collides
let r = reserveAudioFile(dir, model, 'mp3'); // throws 'target already exists'
// after: retry with a fresh timestamp
let r;
for (let i = 0; !r; i++) {
    try { r = reserveAudioFile(dir, model, 'mp3'); }
    catch (e) { if (!String(e.message).includes('target already exists') || i > 2) throw e; await new Promise(s => setTimeout(s, 1100)); }
}
Defensive patterns

Strategy: retry

Validate before calling

import * as fs from 'node:fs';
function targetFree(dir, model, format, now = new Date()) {
    const stamp = now.toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z');
    return !fs.existsSync(require('node:path').join(dir, `${model}-${stamp}.${format}`));
}
// if (!targetFree(dir, model, 'mp3')) wait or pick another dir before calling

Try / catch

async function reserveWithRetry(dir, model, format, attempts = 3) {
    for (let i = 0; i < attempts; i++) {
        try { return reserveAudioFile(dir, model, format, new Date()); }
        catch (e) {
            if (!String(e.message).includes('target already exists') || i === attempts - 1) throw e;
            await new Promise(s => setTimeout(s, 1100)); // fresh timestamp next try
        }
    }
}

Prevention

When it happens

Trigger: The generated filename '<model>-<timestamp>.<format>' already exists in dir — typically two generations within the same second producing an identical ISO-stamp name, or a rerun of the same command.

Common situations: Running the CLI twice in quick succession (same model, same format, same second); a previous partially-failed run left the target file; automated pipelines invoking generation more than once per second.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9ec4c8189e8af58e. Report an issue: GitHub.

Appendix: source

Thrown at clis/minimax/utils.js:188

export function resolveOutputDir(value) {
    const raw = String(value ?? '').trim();
    if (!raw) return path.join(os.homedir(), 'Music', 'minimax');
    if (raw === '~') return os.homedir();
    if (raw.startsWith('~/')) return path.join(os.homedir(), raw.slice(2));
    if (raw.startsWith('~')) throw new ArgumentError(`Unsupported home-directory path: ${raw}`);
    return path.resolve(raw);
}

export function reserveAudioFile(dir, model, format, now = new Date()) {
    const stamp = now.toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z');
    const target = path.join(dir, `${model}-${stamp}.${format}`);
    const lock = `${target}.lock`;
    const staging = `${target}.${process.pid}.${randomUUID()}.tmp`;
    try {
        fs.mkdirSync(dir, { recursive: true });
        if (!fs.statSync(dir).isDirectory()) throw new Error('not a directory');
        fs.accessSync(dir, fs.constants.W_OK);
        if (fs.existsSync(target)) throw new Error('target already exists');
        fs.writeFileSync(lock, String(process.pid), { flag: 'wx', mode: 0o600 });
        if (fs.existsSync(target)) {
            fs.rmSync(lock, { force: true });
            throw new Error('target appeared during reservation');
        }
        return { target, lock, staging };
    } catch (error) {
        throw new CommandExecutionError(`MiniMax music cannot reserve output file ${target}: ${error?.message ?? error}`);
    }
}

export function commitAudioFile(reservation, bytes) {
    try {
        fs.writeFileSync(reservation.staging, bytes, { flag: 'wx', mode: 0o600 });
        // A same-filesystem hard link publishes the complete staging inode and
        // fails if target already exists on POSIX and Windows alike.
        fs.linkSync(reservation.staging, reservation.target);
        cleanupAudioFile(reservation);

View on GitHub (pinned to 49907e53dc)