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

  1. Print the first/last few characters and the length of data.audio to spot truncation or a '0x' prefix/base64 content
  2. If the value is a URL, use requireAudioUrl/download instead of decodeAudioHex
  3. If it looks like base64, decode with Buffer.from(value, 'base64') instead
  4. 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

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


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