jackwener/OpenCLI · error · CommandExecutionError
MiniMax music returned invalid hexadecimal audio
Error message
MiniMax music returned invalid hexadecimal audio
What it means
decodeAudioHex validates the hex payload before decoding: it must be non-empty, have even length (each byte is two hex digits), and contain only hex characters. Any violation throws, since Buffer.from(value, 'hex') would otherwise silently produce truncated or garbage bytes.
Source
Thrown at clis/minimax/utils.js:150
return extraInfo.music_size;
}
export function requireAudioUrl(value) {
let url;
try {
url = new URL(value);
} catch {
throw new CommandExecutionError('MiniMax music returned data.audio that is not a URL');
}
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;
}View on GitHub (pinned to 49907e53dc)
Solutions
- Print the first/last few characters and the length of data.audio to spot truncation or a '0x' prefix/base64 content
- If the value is a URL, use requireAudioUrl/download instead of decodeAudioHex
- If it looks like base64, decode with Buffer.from(value, 'base64') instead
- Increase any HTTP body size limits in your HTTP client so large hex payloads are not truncated
Example fix
// before: decoding whatever arrives const bytes = decodeAudioHex(data.audio, expectedBytes, format); // after: detect base64/hex form first const isHex = data.audio.length % 2 === 0 && /^[0-9a-f]+$/i.test(data.audio); const bytes = isHex ? decodeAudioHex(data.audio, expectedBytes, format) : decodeAudioBase64(data.audio, expectedBytes, format);
Defensive patterns
Strategy: validation
Validate before calling
function looksLikeHex(v) {
return typeof v === 'string' && v.length > 0 && v.length % 2 === 0 && /^[0-9a-f]+$/i.test(v);
}
if (!looksLikeHex(payload?.data?.audio)) {
// choose URL or base64 path, or inspect raw payload
} Type guard
function isHexString(v) {
return typeof v === 'string' && v.length % 2 === 0 && /^[0-9a-f]+$/i.test(v);
} Try / catch
try {
const bytes = decodeAudioHex(value, expectedBytes, format);
} catch (e) {
if (/invalid hexadecimal/.test(e.message)) {
if (/^[A-Za-z0-9+/=]+$/.test(value)) {
// looks like base64 — decode accordingly
} else {
console.error('audio value head:', value.slice(0, 32), 'len:', value.length);
}
} else throw e;
} Prevention
- Raise HTTP client max body size to avoid truncation of large hex payloads
- Strip whitespace/'0x' prefixes before decoding
- Detect payload encoding (hex vs base64 vs URL) before dispatching
- Never pass audio strings through lossy shell/editor pipelines
When it happens
Trigger: data.audio hex string is empty; it has odd length (a character lost to truncation or encoding corruption); it contains non-hex characters (whitespace, '0x' prefix, base64 characters, or a URL pasted into the hex path).
Common situations: HTTP client truncating large response bodies; calling the hex decoder with a URL value from a URL-returning endpoint; copying audio strings through a shell or editor that strips characters; MiniMax returning base64 instead of hex after an API change.
Related errors
- MiniMax music returned data.audio that is not a URL
- MiniMax music response is missing integer data.status
- MiniMax music returned status 1 (in progress) without a resu
- MiniMax music returned unknown data.status ${data.status}
- MiniMax music reported completion without data.audio
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0fbd7944bb3477aa.
Report an issue: GitHub.