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
- Verify the Resource exists and is readable before calling the transcription API (resource.exists() && resource.isReadable()).
- For files inside a JAR, use new ClassPathResource("audio.mp3") or copy to a temp file first rather than FileSystemResource with a JAR path.
- Check file permissions and that the path is correct relative to the process working directory.
- 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
- Check resource.exists() and resource.isReadable() before every transcription call.
- Use ClassPathResource for bundled audio and copy JAR-embedded resources to a temp file first.
- Ensure uploaded temp files are not cleaned up before the transcription request completes.
- Verify file permissions when running in containers or shared volumes.
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
- Failed to read audio speech response
- Failed to cache the resource:
- java.io.IOException
- IOException (wrapped RuntimeException)
- Failed to read resource
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/cec31e9398e6a127.
Report an issue: GitHub.