jackwener/OpenCLI · error · CommandExecutionError
MiniMax music cannot reserve output file ${target}: ${error?
Error message
MiniMax music cannot reserve output file ${target}: ${error?.message ?? error} What it means
reserveAudioFile wraps every failure of the reservation sequence (mkdir, stat, W_OK access check, exclusive lock creation, TOCTOU re-check) in a CommandExecutionError: 'MiniMax music cannot reserve output file <target>: <cause>'. The cause string is appended via error?.message ?? error, so the root reason always appears after the colon.
Source
Thrown at clis/minimax/utils.js:196
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);
return reservation.target;
} catch (error) {
cleanupAudioFile(reservation);
throw new CommandExecutionError(`MiniMax music could not atomically write ${reservation.target}: ${error?.message ?? error}`);
}
}
export function cleanupAudioFile(reservation) {View on GitHub (pinned to 49907e53dc)
Solutions
- Read the cause after the colon: if it mentions EEXIST/.lock, delete the stale `<target>.lock` file and retry.
- If the cause is 'not a directory' or permission denied, pass a --output path that is an existing writable directory.
- Verify write access: `touch <dir>/.writetest`, then fix ownership/ACLs if it fails.
- If two jobs collide concurrently, serialize them or use separate output directories.
Example fix
// before $ minimax music --output /etc # not writable Error: MiniMax music cannot reserve output file /etc/minimax-music-...: EACCES // after $ minimax music --output ~/Music/minimax
Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
function ensureWritableOutputDir(dir) {
const resolved = path.resolve(String(dir ?? '').replace(/^~(?=$|\/)/, os.homedir()));
fs.mkdirSync(resolved, { recursive: true });
if (!fs.statSync(resolved).isDirectory()) throw new Error(`not a directory: ${resolved}`);
fs.accessSync(resolved, fs.constants.W_OK);
return resolved;
} Try / catch
try {
runMinimaxMusic();
} catch (e) {
const m = /cannot reserve output file .*: (.+)$/.exec(e.message);
if (m && m[1].includes('EEXIST')) {
fs.rmSync(`${target}.lock`, { force: true }); // stale lock from crashed run
} else if (m && /EACCES|not a directory/.test(m[1])) {
console.error('Fix --output: must be a writable directory');
} else { throw e; }
} Prevention
- Always pass --output as an existing writable directory, not a file.
- Verify write access with `touch <dir>/.writetest` before long-running jobs.
- Clean up stale <target>.lock files after killing a run.
- Avoid restricted paths like /usr, /etc, or read-only CI mounts as output.
When it happens
Trigger: Any failure inside reserveAudioFile's try block: the --output path is not a directory, the directory is not writable (fs.accessSync W_OK fails), fs.writeFileSync with flag 'wx' fails because <target>.lock already exists (stale lock from a crashed run), or the target appeared during the reservation race.
Common situations: --output pointing to an existing regular file instead of a directory; read-only or permission-restricted output directories (restricted CI workspace, ~/Music/minimax owned by another user); leftover .lock files from killed commands making 'wx' creation throw EEXIST.
Related errors
- File could not be read: ${path}
- FILE_READ_ERROR
- File not found: ${path}
- File must be a readable text file: ${path}
- Receipt file cannot be read: ${receipt}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/b9a030461e391bd4.
Report an issue: GitHub.