moeru-ai/airi · error

Invalid request body

Error message

Invalid request body

What it means

The MiMo speech provider's custom fetch requires the outgoing request body to be a JSON string. When init.body is missing or not a string, the wrapper cannot parse the TTS options (input, model, voice, style) and throws instead of sending a broken request.

Source

Thrown at packages/provider-inference/src/providers/cloud/mimo-audio/index.ts:69

      }),
    ],
  }
}

function createMimoSpeechProvider(config: MimoSpeechConfig) {
  const apiKey = config.apiKey?.trim() ?? ''
  const baseUrl = normalizeBaseUrl(config.baseUrl)
  const defaultModel = config.model || 'mimo-v2.5-tts'
  const defaultVoice = config.voice || 'mimo_default'
  const defaultFormat = config.format || 'wav'

  return {
    speech: () => ({
      baseURL: baseUrl,
      model: defaultModel,
      fetch: async (_input: RequestInfo | URL, init?: RequestInit) => {
        if (!init?.body || typeof init.body !== 'string')
          throw new Error('Invalid request body')

        const body = JSON.parse(init.body) as {
          input?: string
          model?: string
          response_format?: string
          style_prompt?: string
          voice_sample?: string
          voice?: string
        }
        const model = body.model || defaultModel
        const format = body.response_format || defaultFormat
        const stylePrompt = body.style_prompt?.trim() || config.stylePrompt?.trim() || ''
        const voiceSample = body.voice_sample?.trim() || config.voiceSample?.trim() || ''
        const userPrompt = model === 'mimo-v2.5-tts-voiceclone'
          ? stylePrompt
          : stylePrompt || 'Use a natural, clear speaking style.'

        const audio: Record<string, string> = { format }

View on GitHub (pinned to f679616c34)

Solutions

  1. Call the provider through its speech() API so the body is JSON-serialized before the wrapper runs
  2. Inspect any custom fetch chain and ensure it forwards the original init.body string
  3. Avoid overriding body with non-string types when configuring the speech client
  4. In test code, always pass a JSON-string body when invoking the wrapper directly

Example fix

// before
const res = await customFetch(url) // no body
// after
const res = await customFetch(url, { method: 'POST', body: JSON.stringify({ model, input, voice }) })
Defensive patterns

Strategy: validation

Validate before calling

const body = init?.body
if (typeof body !== 'string' || !body) throw new Error('MiMo speech request requires a JSON string body')
JSON.parse(body)

Type guard

function hasStringBody(init?: RequestInit): init is RequestInit & { body: string } {
  return typeof init?.body === 'string' && init.body.length > 0
}

Try / catch

try {
  const audio = await provider.speech().generate(options)
} catch (e) {
  if (e instanceof Error && e.message === 'Invalid request body') {
    // ensure the SDK client serializes a JSON string body
  }
}

Prevention

When it happens

Trigger: Calling the MiMo speech API through a path that does not produce a string body: a custom fetch that supplies no body, a FormData/stream/Blob body, or calling the wrapped fetch directly without init.

Common situations: Middleware or proxy fetch wrapping that drops the body, invoking the fetch function manually for testing, or using an SDK client version that serializes bodies differently.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@f679616c34 (2026-09-08). Data as JSON: /api/errors/03067cd12aedfa99. Report an issue: GitHub.