spring-projects/spring-ai · warning

No speech response returned for request: + requestContext.re

Error message

No speech response returned for request: + requestContext.request

What it means

Warning logged by ElevenLabsTextToSpeechModel.call() inside the retry-wrapped request when the textToSpeech HTTP response has a null body. The method returns an empty byte[0] audio payload in the TextToSpeechResponse rather than throwing, so callers may silently write/play zero-length audio.

Source

Thrown at models/spring-ai-elevenlabs/src/main/java/org/springframework/ai/elevenlabs/ElevenLabsTextToSpeechModel.java:82

		this.elevenLabsApi = elevenLabsApi;
		this.options = options;
		this.retryTemplate = retryTemplate;
	}

	public static Builder builder() {
		return new Builder();
	}

	@Override
	public TextToSpeechResponse call(TextToSpeechPrompt prompt) {
		RequestContext requestContext = prepareRequest(prompt);

		byte[] audioData = RetryUtils.execute(this.retryTemplate, () -> {
			var response = this.elevenLabsApi.textToSpeech(requestContext.request, requestContext.voiceId,
					requestContext.queryParameters);
			if (response.getBody() == null) {
				if (logger.isWarnEnabled()) {
					logger.warn("No speech response returned for request: " + requestContext.request);
				}
				return new byte[0];
			}
			return response.getBody();
		});

		return new TextToSpeechResponse(List.of(new Speech(audioData)));
	}

	@Override
	public Flux<TextToSpeechResponse> stream(TextToSpeechPrompt prompt) {
		RequestContext requestContext = prepareRequest(prompt);

		return RetryUtils.execute(this.retryTemplate, () -> this.elevenLabsApi
			.textToSpeechStream(requestContext.request, requestContext.voiceId, requestContext.queryParameters)
			.map(entity -> new TextToSpeechResponse(List.of(new Speech(Objects.requireNonNull(entity.getBody()))))));
	}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Verify the ElevenLabs API key and remaining character quota in your account dashboard.
  2. Confirm the voiceId passed in the request context still exists in your ElevenLabs account.
  3. Check the raw HTTP response with an interceptor; a 4xx body may be swallowed as null by generic error handling.
  4. Treat byte[0] speech output as failure in application code and retry or surface an error.

Example fix

// before
byte[] audio = ttsModel.call(new TextToSpeechRequest(text, voiceId, null)).getAudio();
FileOutputStream out = new FileOutputStream(f); // writes empty file silently
// after
if (audio == null || audio.length == 0) throw new IllegalStateException("TTS returned no audio");
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: verify voiceId exists and quota remains
assert voiceId != null && !voiceId.isBlank();

Type guard

static boolean hasAudio(TextToSpeechResponse r) {
    return r != null && r.getSpeech() != null && r.getSpeech().stream().anyMatch(s -> s.getAudio() != null && s.getAudio().length > 0);
}

Try / catch

TextToSpeechResponse r = ttsModel.call(req);
if (!hasAudio(r)) throw new IllegalStateException("ElevenLabs returned no audio; check quota/key/voiceId");

Prevention

When it happens

Trigger: elevenLabsApi.textToSpeech(requestContext.request, voiceId, queryParameters) returns a ResponseEntity whose getBody() is null — empty response body from ElevenLabs, or deserialization yielding null after retries.

Common situations: Exhausted ElevenLabs quota (Free tier limits) returning unusual empty responses; invalid or deleted voiceId; API outage or gateway stripping the body; expired/invalid API key returning an unexpected empty 2xx.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/489e0f90978e2e6c. Report an issue: GitHub.