jackwener/OpenCLI · error · CommandExecutionError

MiniMax music could not atomically write ${reservation.targe

Error message

MiniMax music could not atomically write ${reservation.target}: ${error?.message ?? error}

What it means

commitAudioFile writes decoded audio bytes to a private staging file and publishes it atomically via fs.linkSync (hard link staging -> target), which fails if the target already exists. On any failure (staging write error, link error such as EEXIST/EXDEV, disk full) it removes staging and lock files and throws CommandExecutionError 'MiniMax music could not atomically write <target>: <cause>'.

Source

Thrown at clis/minimax/utils.js:210

            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) {
    if (!reservation) return;
    fs.rmSync(reservation.staging, { force: true });
    fs.rmSync(reservation.lock, { force: true });
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check free disk space on the output volume (`df -h <dir>`) if the cause is ENOSPC and free space.
  2. If the cause is EEXIST, delete or rename the existing target file and rerun.
  3. If the cause is EXDEV, keep --output on the same filesystem as the temp dir, or fall back to fs.renameSync.
  4. Fix directory write permissions if the cause is EACCES on staging or target creation.

Example fix

// before
fs.linkSync(reservation.staging, reservation.target); // EXDEV across mounts

// after (rename fallback stays atomic and works when link is unsupported)
try { fs.linkSync(reservation.staging, reservation.target); }
catch (e) { if (e.code === 'EXDEV') fs.renameSync(reservation.staging, reservation.target); else throw e; }
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
function preflightCommit(target, dir) {
  fs.accessSync(dir, fs.constants.W_OK);
  if (fs.existsSync(target)) throw new Error(`target exists: ${target}`);
  const st = fs.statfsSync(dir);
  if (st.bavail * st.bsize < 50 * 1024 * 1024) throw new Error('low disk space');
  if (fs.statfsSync(os.tmpdir()).dev !== st.dev) {
    console.warn('staging/tmp on different device: fs.linkSync may fail with EXDEV');
  }
}

Try / catch

try {
  commitAudioFile(reservation, bytes);
} catch (e) {
  if (/atomically write|EEXIST/.test(e.message)) {
    // target raced: remove or rename existing file, re-reserve, retry once
  } else if (/ENOSPC/.test(e.message)) {
    console.error('Free disk space and rerun');
  } else { throw e; }
} finally {
  cleanupAudioFile(reservation); // idempotent; clears staging and lock
}

Prevention

When it happens

Trigger: fs.writeFileSync(staging, bytes, {flag:'wx'}) fails (disk full, permission denied), or fs.linkSync(staging, target) fails — most commonly EEXIST because the target appeared between reservation and commit, or EXDEV when staging and target are on different filesystems.

Common situations: Disk quota/full volume while writing large WAV audio; another process creating the same target path before commit; output directory on a different mount point so hard links are impossible; antivirus/backup software touching the staging tmp file mid-write.

Related errors


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