{"record":{"id":"5cae98387429d13d","repo":"spring-projects/spring-ai","slug":"only-one-of-template-or-resource-can-be-set","errorCode":null,"errorMessage":"Only one of template or resource can be set","messagePattern":"Only one of template or resource can be set","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java","lineNumber":260,"sourceCode":"\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder variables(Map<String, Object> variables) {\n\t\t\tAssert.notNull(variables, \"variables cannot be null\");\n\t\t\tAssert.noNullElements(variables.keySet(), \"variables keys cannot be null\");\n\t\t\tthis.variables = variables;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder renderer(TemplateRenderer renderer) {\n\t\t\tAssert.notNull(renderer, \"renderer cannot be null\");\n\t\t\tthis.renderer = renderer;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic PromptTemplate build() {\n\t\t\tif (this.template != null && this.resource != null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Only one of template or resource can be set\");\n\t\t\t}\n\t\t\telse if (this.resource != null) {\n\t\t\t\treturn new PromptTemplate(this.resource, this.variables, this.renderer);\n\t\t\t}\n\t\t\telse if (this.template != null) {\n\t\t\t\treturn new PromptTemplate(this.template, this.variables, this.renderer);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new IllegalStateException(\"Neither template nor resource is set\");\n\t\t\t}\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":242,"sourceCodeEnd":276,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/chat/prompt/PromptTemplate.java#L242-L276","documentation":"PromptTemplate.Builder.build() enforces that the template can come from exactly one source: an inline string template or a Resource. Setting both makes the source ambiguous, so build() throws this IllegalArgumentException.","triggerScenarios":"Calling PromptTemplate.builder().template(\"...\").resource(resource)...build() — i.e. both setters invoked on the same builder.","commonSituations":"Reusable builder code that unconditionally sets a default template and then optionally a resource file; copy-pasted fluent chains accumulating both sources.","solutions":["Set only one source: remove the .template(...) call when using .resource(...), or vice versa.","If you want file-with-fallback, choose the source conditionally before building.","Create two separate builders instead of reusing one builder object for both variants."],"exampleFix":"// before\nPromptTemplate.builder().template(\"Hello {name}\").resource(res).build();\n// after\nPromptTemplate.builder().resource(res).build();","handlingStrategy":"validation","validationCode":"if (b.templateSet && b.resourceSet) throw new IllegalStateException(\"Set only one of template or resource\");","typeGuard":null,"tryCatchPattern":"try { return builder.build(); } catch (IllegalArgumentException e) { logger.error(\"both template and resource set\", e); }","preventionTips":["Pick one source style per template (file OR inline) as a project convention","Don't reuse a builder instance across conditional branches that set different sources","Add a unit test per builder configuration"],"tags":["builder","mutually-exclusive","template"],"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-14T11:17:12.474Z"}