fix(stt-live-audio): cancel ElevenLabs error response body (#110759)

Avoid buffering unbounded provider error streams and cover the resource lifecycle with a deterministic cancellation contract.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
tzy-17
2026-07-18 21:48:04 +01:00
committed by GitHub
co-authored by Peter Steinberger
parent 6646719c05
commit 09c46fb682
2 changed files with 38 additions and 0 deletions
+35
View File
@@ -1,5 +1,6 @@
// Elevenlabs tests cover tts plugin behavior.
import { MAX_AUDIO_BYTES } from "openclaw/plugin-sdk/media-runtime";
import { synthesizeElevenLabsLiveSpeech } from "openclaw/plugin-sdk/provider-test-contracts";
import { afterEach, describe, expect, it, vi } from "vitest";
import { createStreamingErrorResponse } from "../test-support/streaming-error-response.js";
import { elevenLabsTTS, elevenLabsTTSStream } from "./tts.js";
@@ -326,3 +327,37 @@ describe("elevenlabs tts diagnostics", () => {
);
});
});
describe("elevenlabs live audio helper error-path body release", () => {
const originalFetch = globalThis.fetch;
afterEach(() => {
globalThis.fetch = originalFetch;
});
it("cancels an unread streaming error body when ElevenLabs returns non-2xx", async () => {
const cancel = vi.fn();
const response = new Response(
new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array([1, 2, 3]));
},
cancel,
}),
{ status: 401 },
);
globalThis.fetch = vi.fn(async () => response) as typeof fetch;
await expect(
synthesizeElevenLabsLiveSpeech({
text: "OpenClaw leak check.",
apiKey: "x",
outputFormat: "mp3_44100_128",
timeoutMs: 1_000,
}),
).rejects.toThrow("ElevenLabs live TTS failed (401)");
expect(cancel).toHaveBeenCalledOnce();
expect(response.bodyUsed).toBe(true);
});
});
@@ -71,6 +71,9 @@ export async function synthesizeElevenLabsLiveSpeech(params: {
signal: controller.signal,
});
if (!response.ok) {
// Error payloads are not used by the live fixture. Cancel instead of buffering an
// untrusted or unbounded body so Undici can release the connection promptly.
await response.body?.cancel().catch(() => undefined);
throw new Error(`ElevenLabs live TTS failed (${response.status})`);
}
return Buffer.from(await response.arrayBuffer());