jackwener/OpenCLI · error · CommandExecutionError
MiniMax music returned bytes that are not an MP3 file
Error message
MiniMax music returned bytes that are not an MP3 file
What it means
decodeAudioHex validates that hex-decoded audio matches the requested MP3 container: isMp3() accepts bytes starting with an 'ID3' tag or a valid MPEG frame sync (0xFF followed by 0xE0-masked byte). If neither signature is present, the library throws this CommandExecutionError because MiniMax returned audio that is not decodable MP3.
Source
Thrown at clis/minimax/utils.js:160
if (url.protocol !== 'https:') {
throw new CommandExecutionError(`MiniMax music returned a non-HTTPS audio URL (${url.protocol})`);
}
return url.toString();
}
export function decodeAudioHex(value, expectedBytes, format) {
if (value.length === 0 || value.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(value)) {
throw new CommandExecutionError('MiniMax music returned invalid hexadecimal audio');
}
const bytes = Buffer.from(value, 'hex');
if (expectedBytes != null && bytes.length !== expectedBytes) {
throw new CommandExecutionError(`MiniMax music audio size mismatch (expected ${expectedBytes} bytes, got ${bytes.length})`);
}
if (format === 'wav' && (bytes.length < 12 || bytes.subarray(0, 4).toString('ascii') !== 'RIFF' || bytes.subarray(8, 12).toString('ascii') !== 'WAVE')) {
throw new CommandExecutionError('MiniMax music returned bytes that are not a WAV file');
}
if (format === 'mp3' && !isMp3(bytes)) {
throw new CommandExecutionError('MiniMax music returned bytes that are not an MP3 file');
}
return bytes;
}
function isMp3(bytes) {
return bytes.length >= 3 && bytes.subarray(0, 3).toString('ascii') === 'ID3'
|| bytes.length >= 2 && bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0;
}
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);
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Check the request sets audio_setting.format='mp3' and regenerate
- Inspect the first bytes of the decoded buffer — if they read 'RIFF'/'WAVE', switch to format='wav' and save with a .wav extension
- Retry the API call; capture base_resp/trace_id if it recurs and contact MiniMax support
- Validate data.audio hex integrity upstream (no truncation or whitespace) before decode
Example fix
// before
const bytes = decodeAudioHex(data.audio, expectedBytes, 'mp3'); // got RIFF bytes -> throws
// after: align with the actual payload format
if (bytes.subarray(0, 4).toString('ascii') === 'RIFF') {
fs.writeFileSync('out.wav', decodeAudioHex(data.audio, expectedBytes, 'wav'));
} Defensive patterns
Strategy: validation
Validate before calling
function looksLikeMp3(hex) {
if (!/^[0-9a-f]+$/i.test(hex) || hex.length % 2 !== 0) return false;
const bytes = Buffer.from(hex, 'hex');
return bytes.length >= 2
&& (bytes.subarray(0, 3).toString('ascii') === 'ID3'
|| (bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0));
}
// before decodeAudioHex(..., 'mp3'): if (!looksLikeMp3(data.audio)) switch format or retry Type guard
function isMp3Buffer(bytes) {
return Buffer.isBuffer(bytes) && bytes.length >= 2
&& (bytes.subarray(0, 3).toString('ascii') === 'ID3'
|| (bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0));
} Try / catch
try {
const bytes = decodeAudioHex(data.audio, expectedBytes, 'mp3');
} catch (e) {
if (String(e.message).includes('not an MP3 file')) {
const wav = decodeAudioHex(data.audio, expectedBytes, 'wav');
fs.writeFileSync(out + '.wav', wav);
} else throw e;
} Prevention
- Keep audio_setting.format in the request aligned with the extension you save
- Validate ID3/frame-sync magic bytes before writing files
- Retry generation once on format mismatch; persist trace_id for support
- Add a unit test feeding a known WAV hex payload to catch regressions
When it happens
Trigger: Calling decodeAudioHex with format='mp3' while the decoded bytes lack an ID3 header and MPEG sync word — typically WAV (RIFF) bytes returned despite audio_setting.format='mp3', or corrupt/truncated data.
Common situations: Requesting mp3 but the MiniMax endpoint emits WAV; the hex payload is truncated so the first frame bytes are missing; intermediate proxies altering the payload.
Related errors
- MiniMax music returned bytes that are not a WAV file
- MiniMax music returned data.audio that is not a URL
- MiniMax music returned invalid hexadecimal audio
- ${raw} is not a Douyin sec_uid
- designer must be a Dribbble username or profile slug
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/668c46015f71576f.
Report an issue: GitHub.