{"record":{"id":"15d959528d24a596","repo":"nexu-io/open-design","slug":"openai-speech-returned-zero-bytes","errorCode":null,"errorMessage":"openai speech returned zero bytes","messagePattern":"openai speech returned zero bytes","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/media/index.ts","lineNumber":1374,"sourceCode":"  };\n  if (azure) {\n    headers['api-key'] = credentials.apiKey;\n  }\n\n  const resp = await fetch(url, withMediaRequestInit(ctx, {\n    method: 'POST',\n    headers,\n    body: JSON.stringify(body),\n  }));\n  if (!resp.ok) {\n    const text = await resp.text();\n    const tag = azure ? 'azure-openai' : 'openai';\n    throw new Error(`${tag} speech ${resp.status}: ${truncate(text, 240)}`);\n  }\n  const arr = await resp.arrayBuffer();\n  const bytes = Buffer.from(arr);\n  if (bytes.length === 0) {\n    throw new Error('openai speech returned zero bytes');\n  }\n  const tag = azure ? 'azure-openai' : 'openai';\n  const noteBits = [`${tag}/${ctx.wireModel}`, voiceId, `${format}`, `${bytes.length} bytes`];\n  if (instructions) noteBits.splice(2, 0, 'styled');\n  return {\n    bytes,\n    providerNote: noteBits.join(' · '),\n    suggestedExt: format === 'opus' ? '.ogg' : `.${format}`,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Provider: Volcengine Ark — Doubao Seedance 2.0 video.\n//\n// Docs:\n//   POST /api/v3/contents/generations/tasks   → { id }\n//   GET  /api/v3/contents/generations/tasks/{id} → { status, content: { video_url } }\n// We submit, poll until succeeded/failed, then fetch the produced","sourceCodeStart":1356,"sourceCodeEnd":1392,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/media/index.ts#L1356-L1392","documentation":"Thrown after the speech endpoint returns HTTP 2xx but the body decodes to zero bytes (`bytes.length === 0`). It guards against a provider or intermediary that reports success while delivering no audio, which would otherwise write an empty file and look like a successful generation to the agent.","triggerScenarios":"A 2xx response whose `arrayBuffer()` resolves to length 0. Seen with a misconfigured reverse proxy/gateway stripping the binary `audio/*` body, an Azure deployment returning `200` with no audio for an unsupported `response_format`, or an edge content-moderation path that yields no audio without an error status.","commonSituations":"(1) A corporate proxy re-encoding and emptying the audio body; (2) requesting an unsupported `response_format` (e.g. `opus` against a deployment that only serves `mp3`); (3) transient provider hiccup returning a 200 with a truncated body.","solutions":["Retry once — transient empty bodies from the provider usually succeed on the next call.","Confirm the `response_format`/`format` is supported by the model and deployment (`mp3` is universal; `opus`/`aac`/`flac`/`wav`/`pcm` vary by deployment).","If behind a proxy, bypass it or confirm it passes binary `Content-Type: audio/*` bodies unchanged."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let lastErr: unknown;\nfor (let attempt = 0; attempt < 2; attempt++) {\n  try { return await renderOpenAISpeech(ctx, credentials); }\n  catch (err) {\n    lastErr = err;\n    if (/zero bytes/.test(err instanceof Error ? err.message : '')) continue;\n    throw err;\n  }\n}\nthrow lastErr;","preventionTips":["Treat a 200-with-empty-body as retryable; one retry clears most transient cases.","Confirm the requested `response_format` is supported by the deployment before relying on it.","If behind a proxy, verify it forwards binary `audio/*` bodies unchanged."],"tags":["openai","tts","empty-response","provider-error"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}