{"record":{"id":"cec31e9398e6a127","repo":"spring-projects/spring-ai","slug":"failed-to-read-resource","errorCode":null,"errorMessage":"Failed to read resource: ","messagePattern":"Failed to read resource: ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java","lineNumber":291,"sourceCode":"\t}\n\n\tprivate static String extractStreamEventText(TranscriptionStreamEvent event) {\n\t\tif (event.isTranscriptTextDelta()) {\n\t\t\treturn event.asTranscriptTextDelta().delta();\n\t\t}\n\t\tif (event.isTranscriptTextSegment()) {\n\t\t\treturn event.asTranscriptTextSegment().text();\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tprivate static InputStream openStream(Resource resource) {\n\t\tAssert.notNull(resource, \"Resource must not be null\");\n\t\ttry {\n\t\t\treturn resource.getInputStream();\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new IllegalArgumentException(\"Failed to read resource: \" + resource, e);\n\t\t}\n\t}\n\n\tprivate static String getFilename(Resource audioResource) {\n\t\tString filename = audioResource.getFilename();\n\t\tif (filename == null) {\n\t\t\tfilename = \"audio\";\n\t\t}\n\t\treturn filename;\n\t}\n\n\t/**\n\t * Builder for creating {@link OpenAiAudioTranscriptionModel} instances.\n\t */\n\tpublic static final class Builder {\n\n\t\tprivate @Nullable OpenAIClient openAiClient;\n","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiAudioTranscriptionModel.java#L273-L309","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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.)."],"exampleFix":"// before\nResource audio = new FileSystemResource(\"/tmp/upload.wav\");\nmodel.call(new AudioTranscriptionPrompt(audio, options)); // fails if deleted\n// after\nResource audio = new FileSystemResource(\"/tmp/upload.wav\");\nAssert.isTrue(audio.exists() && audio.isReadable(), \"Audio resource missing/unreadable: \" + audio);\nmodel.call(new AudioTranscriptionPrompt(audio, options));","handlingStrategy":"validation","validationCode":"void requireReadableAudio(Resource r) {\n    if (r == null) throw new IllegalArgumentException(\"Audio resource must not be null\");\n    if (!r.exists()) throw new IllegalArgumentException(\"Audio resource does not exist: \" + r);\n    if (!r.isReadable()) throw new IllegalArgumentException(\"Audio resource is not readable: \" + r);\n}","typeGuard":"boolean isUsableAudioResource(Resource r) {\n    try {\n        return r != null && r.exists() && r.isReadable();\n    } catch (Exception e) {\n        return false;\n    }\n}","tryCatchPattern":"try {\n    transcriptionModel.call(new AudioTranscriptionPrompt(resource, options));\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().startsWith(\"Failed to read resource:\")) {\n        logger.error(\"Audio resource unreadable: {} cause: {}\", resource, e.getCause());\n        throw new UnreadableAudioException(resource, e);\n    } else throw e;\n}","preventionTips":["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."],"tags":["resource","io","openai","audio","transcription"],"backgroundTag":"file-read-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}