{"record":{"id":"9ec4c8189e8af58e","repo":"jackwener/OpenCLI","slug":"target-already-exists","errorCode":null,"errorMessage":"target already exists","messagePattern":"target already exists","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/minimax/utils.js","lineNumber":188,"sourceCode":"export function resolveOutputDir(value) {\n    const raw = String(value ?? '').trim();\n    if (!raw) return path.join(os.homedir(), 'Music', 'minimax');\n    if (raw === '~') return os.homedir();\n    if (raw.startsWith('~/')) return path.join(os.homedir(), raw.slice(2));\n    if (raw.startsWith('~')) throw new ArgumentError(`Unsupported home-directory path: ${raw}`);\n    return path.resolve(raw);\n}\n\nexport function reserveAudioFile(dir, model, format, now = new Date()) {\n    const stamp = now.toISOString().replace(/[-:]/g, '').replace(/\\.\\d+Z$/, 'Z');\n    const target = path.join(dir, `${model}-${stamp}.${format}`);\n    const lock = `${target}.lock`;\n    const staging = `${target}.${process.pid}.${randomUUID()}.tmp`;\n    try {\n        fs.mkdirSync(dir, { recursive: true });\n        if (!fs.statSync(dir).isDirectory()) throw new Error('not a directory');\n        fs.accessSync(dir, fs.constants.W_OK);\n        if (fs.existsSync(target)) throw new Error('target already exists');\n        fs.writeFileSync(lock, String(process.pid), { flag: 'wx', mode: 0o600 });\n        if (fs.existsSync(target)) {\n            fs.rmSync(lock, { force: true });\n            throw new Error('target appeared during reservation');\n        }\n        return { target, lock, staging };\n    } catch (error) {\n        throw new CommandExecutionError(`MiniMax music cannot reserve output file ${target}: ${error?.message ?? error}`);\n    }\n}\n\nexport function commitAudioFile(reservation, bytes) {\n    try {\n        fs.writeFileSync(reservation.staging, bytes, { flag: 'wx', mode: 0o600 });\n        // A same-filesystem hard link publishes the complete staging inode and\n        // fails if target already exists on POSIX and Windows alike.\n        fs.linkSync(reservation.staging, reservation.target);\n        cleanupAudioFile(reservation);","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/minimax/utils.js#L170-L206","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wait at least one second and re-run so the ISO-timestamp filename differs","Choose a different output directory or move/rename the existing file","Delete the stale target file if it is from a failed earlier run: rm <target> (also remove <target>.lock if left behind)","Wrap the call in a retry that regenerates with a new Date() to get a fresh stamp"],"exampleFix":"// before: second call in the same second collides\nlet r = reserveAudioFile(dir, model, 'mp3'); // throws 'target already exists'\n// after: retry with a fresh timestamp\nlet r;\nfor (let i = 0; !r; i++) {\n    try { r = reserveAudioFile(dir, model, 'mp3'); }\n    catch (e) { if (!String(e.message).includes('target already exists') || i > 2) throw e; await new Promise(s => setTimeout(s, 1100)); }\n}","handlingStrategy":"retry","validationCode":"import * as fs from 'node:fs';\nfunction targetFree(dir, model, format, now = new Date()) {\n    const stamp = now.toISOString().replace(/[-:]/g, '').replace(/\\.\\d+Z$/, 'Z');\n    return !fs.existsSync(require('node:path').join(dir, `${model}-${stamp}.${format}`));\n}\n// if (!targetFree(dir, model, 'mp3')) wait or pick another dir before calling","typeGuard":null,"tryCatchPattern":"async function reserveWithRetry(dir, model, format, attempts = 3) {\n    for (let i = 0; i < attempts; i++) {\n        try { return reserveAudioFile(dir, model, format, new Date()); }\n        catch (e) {\n            if (!String(e.message).includes('target already exists') || i === attempts - 1) throw e;\n            await new Promise(s => setTimeout(s, 1100)); // fresh timestamp next try\n        }\n    }\n}","preventionTips":["Avoid rapid successive generations of the same model+format within one second","Clean up stale targets and .lock files from failed runs before rerunning","Write output to a fresh/timestamped or run-scoped directory in pipelines","Catch the wrapped CommandExecutionError and surface the target path so operators can clear it"],"tags":["minimax","filesystem","file-exists","collision"],"backgroundTag":"file-already-exists","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}