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
- Call the provider through its speech() API so the body is JSON-serialized before the wrapper runs
- Inspect any custom fetch chain and ensure it forwards the original init.body string
- Avoid overriding body with non-string types when configuring the speech client
- 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
- Use the provider's speech() API as the only entry point
- Do not wrap the fetch with middleware that replaces or consumes the body
- When invoking the fetch manually in tests, always pass JSON.stringify(options)
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
- Invalid request body
- Invalid request body
- Invalid request body
- MiMo voice clone requires a base64 audio sample in data URI
- MiMo voice design requires a style prompt in the user messag
AI-assisted analysis of moeru-ai/airi@f679616c34 (2026-09-08).
Data as JSON: /api/errors/03067cd12aedfa99.
Report an issue: GitHub.