{"record":{"id":"c5dc03da59e65a7f","repo":"spring-projects/spring-ai","slug":"java-io-ioexception-c5dc03","errorCode":null,"errorMessage":"java.io.IOException","messagePattern":"java\\.io\\.IOException","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java","lineNumber":154,"sourceCode":"\n\tpublic Builder defaultOptions(ChatOptions.Builder customizer) {\n\t\tthis.defaultRequest.options(customizer);\n\t\treturn this;\n\t}\n\n\tpublic Builder defaultUser(String text) {\n\t\tthis.defaultRequest.user(text);\n\t\treturn this;\n\t}\n\n\tpublic Builder defaultUser(Resource text, Charset charset) {\n\t\tAssert.notNull(text, \"text cannot be null\");\n\t\tAssert.notNull(charset, \"charset cannot be null\");\n\t\ttry {\n\t\t\tthis.defaultRequest.user(text.getContentAsString(charset));\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic Builder defaultUser(Resource text) {\n\t\treturn this.defaultUser(text, Charset.defaultCharset());\n\t}\n\n\tpublic Builder defaultUser(Consumer<PromptUserSpec> userSpecConsumer) {\n\t\tthis.defaultRequest.user(userSpecConsumer);\n\t\treturn this;\n\t}\n\n\tpublic Builder defaultSystem(String text) {\n\t\tthis.defaultRequest.system(text);\n\t\treturn this;\n\t}\n","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClientBuilder.java#L136-L172","documentation":"Builder.defaultUser(Resource, Charset) reads the resource text with getContentAsString(charset); an IOException (unreadable/missing resource) is wrapped and rethrown as a plain RuntimeException. The wrapping hides the underlying cause from the top-level message.","triggerScenarios":"ChatClient.builder().defaultUser(Resource text, Charset charset) (or defaultUser(Resource)) where the Resource cannot be read: nonexistent classpath/file resource, closed stream, or I/O failure.","commonSituations":"Building a shared ChatClient bean with a default user prompt loaded from a resource that wasn't packaged or whose path changed; charset issues with malformed input streams.","solutions":["Check that the Resource exists and is readable before calling defaultUser (resource.exists()).","Read e.getCause() to see the actual IOException and fix the path/stream.","Fall back to defaultUser(String) with content loaded and validated by your own code.","Ensure the resource is on the runtime classpath of the deployed artifact."],"exampleFix":"// before\nbuilder.defaultUser(new ClassPathResource(\"prompts/user.txt\"));\n// after\nResource r = new ClassPathResource(\"prompts/user.txt\");\nif (!r.exists()) throw new IllegalStateException(\"user prompt resource missing\");\nbuilder.defaultUser(r);","handlingStrategy":"validation","validationCode":"Resource r = new ClassPathResource(\"prompts/user.txt\");\nif (!r.exists()) throw new IllegalStateException(\"missing default user resource\");\nbuilder.defaultUser(r);","typeGuard":null,"tryCatchPattern":"try { builder.defaultUser(resource); } catch (RuntimeException e) { log.error(\"defaultUser resource read failed\", e.getCause()); }","preventionTips":["Verify the resource exists at startup when building shared ChatClient beans.","Keep prompt resources under src/main/resources so they're packaged.","Use defaultUser(String) for content you've already loaded and validated."],"tags":["io","resource-loading","builder","spring-ai"],"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"}