{"record":{"id":"313096b799f7a386","repo":"spring-projects/spring-ai","slug":"textcontent-and-resource-cannot-be-set-at-the-same-313096","errorCode":null,"errorMessage":"textContent and resource cannot be set at the same time","messagePattern":"textContent and resource cannot be set at the same time","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java","lineNumber":122,"sourceCode":"\n\t\tpublic Builder media(List<Media> media) {\n\t\t\tthis.media = media;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder media(Media... media) {\n\t\t\tthis.media = Arrays.asList(media);\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder metadata(Map<String, Object> metadata) {\n\t\t\tthis.metadata = metadata;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic UserMessage build() {\n\t\t\tif (StringUtils.hasText(this.textContent) && this.resource != null) {\n\t\t\t\tthrow new IllegalArgumentException(\"textContent and resource cannot be set at the same time\");\n\t\t\t}\n\t\t\telse if (this.resource != null) {\n\t\t\t\tthis.textContent = MessageUtils.readResource(this.resource);\n\t\t\t}\n\t\t\treturn new UserMessage(this.textContent, this.media, this.metadata);\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":104,"sourceCodeEnd":133,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/chat/messages/UserMessage.java#L104-L133","documentation":"UserMessage.Builder.build() enforces mutual exclusivity between textContent and resource: the message text may come either from an inline string or from a Resource, not both. Supplying both throws IllegalArgumentException.","triggerScenarios":"Calling UserMessage.builder().text(\"hi\").resource(myResource).build(); chaining both text and resource setters before build().","commonSituations":"Migrating from text-based prompts to resource-based prompts and leaving both setters in the chain; templating code that conditionally adds text but also always sets a default resource.","solutions":["Keep only one of text(...) / resource(...) in the builder chain","If the resource is optional fallback, wrap the choice in an if/else so only one is set","Read the resource to a String yourself and pass it via text(...) when you need to combine content programmatically"],"exampleFix":"// before\nUserMessage msg = UserMessage.builder()\n    .text(\"Summarize this\").resource(new ClassPathResource(\"input.txt\")).build();\n// after\nUserMessage msg = UserMessage.builder()\n    .resource(new ClassPathResource(\"input.txt\")).build();","handlingStrategy":"validation","validationCode":"if (StringUtils.hasText(text) && resource != null) {\n    throw new IllegalArgumentException(\"Set either text or resource, not both\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    UserMessage msg = builder.build();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"textContent and resource\")) { /* rebuild with a single source */ }\n    throw e;\n}","preventionTips":["Keep exactly one of text/resource in the builder chain","Prefer reading resources yourself and passing strings when combining content","Cover builder paths with tests for both text-only and resource-only cases"],"tags":["builder","validation","user-message","spring-ai"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}