spring-projects/spring-ai · error · IllegalArgumentException

Failed to read resource:

Error message

Failed to read resource: 

What it means

OpenAiAudioTranscriptionModel.openStream(Resource) calls resource.getInputStream() to obtain the audio bytes for the transcription upload. If the Resource exists but its underlying stream cannot be opened (IOException), the method rethrows it as an IllegalArgumentException with this message — the library treats an unreadable resource as an invalid argument to the transcription API.

Source

Thrown at models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java:291

	}

	private static String extractStreamEventText(TranscriptionStreamEvent event) {
		if (event.isTranscriptTextDelta()) {
			return event.asTranscriptTextDelta().delta();
		}
		if (event.isTranscriptTextSegment()) {
			return event.asTranscriptTextSegment().text();
		}
		return "";
	}

	private static InputStream openStream(Resource resource) {
		Assert.notNull(resource, "Resource must not be null");
		try {
			return resource.getInputStream();
		}
		catch (IOException e) {
			throw new IllegalArgumentException("Failed to read resource: " + resource, e);
		}
	}

	private static String getFilename(Resource audioResource) {
		String filename = audioResource.getFilename();
		if (filename == null) {
			filename = "audio";
		}
		return filename;
	}

	/**
	 * Builder for creating {@link OpenAiAudioTranscriptionModel} instances.
	 */
	public static final class Builder {

		private @Nullable OpenAIClient openAiClient;

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Verify the Resource exists and is readable before calling the transcription API (resource.exists() && resource.isReadable()).
  2. For files inside a JAR, use new ClassPathResource("audio.mp3") or copy to a temp file first rather than FileSystemResource with a JAR path.
  3. Check file permissions and that the path is correct relative to the process working directory.
  4. Inspect the wrapped IOException cause for the precise reason (FileNotFoundException, AccessDeniedException, etc.).

Example fix

// before
Resource audio = new FileSystemResource("/tmp/upload.wav");
model.call(new AudioTranscriptionPrompt(audio, options)); // fails if deleted
// after
Resource audio = new FileSystemResource("/tmp/upload.wav");
Assert.isTrue(audio.exists() && audio.isReadable(), "Audio resource missing/unreadable: " + audio);
model.call(new AudioTranscriptionPrompt(audio, options));
Defensive patterns

Strategy: validation

Validate before calling

void requireReadableAudio(Resource r) {
    if (r == null) throw new IllegalArgumentException("Audio resource must not be null");
    if (!r.exists()) throw new IllegalArgumentException("Audio resource does not exist: " + r);
    if (!r.isReadable()) throw new IllegalArgumentException("Audio resource is not readable: " + r);
}

Type guard

boolean isUsableAudioResource(Resource r) {
    try {
        return r != null && r.exists() && r.isReadable();
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    transcriptionModel.call(new AudioTranscriptionPrompt(resource, options));
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Failed to read resource:")) {
        logger.error("Audio resource unreadable: {} cause: {}", resource, e.getCause());
        throw new UnreadableAudioException(resource, e);
    } else throw e;
}

Prevention

When it happens

Trigger: Passing a FileSystemResource/ClassPathResource/UrlResource whose file was deleted, moved, or is unreadable (permissions), a classpath resource not on the classpath at runtime, or a URL resource pointing at an unreachable location when fileField() prepares the multipart request.

Common situations: Uploading a temp file that was already deleted after request processing; packaging audio in a JAR and using FileSystemResource instead of ClassPathResource; missing read permissions after upload to a shared volume; typo'd file path or wrong working directory in containerized deployments.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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