{"record":{"id":"cd0eea16f4b38120","repo":"spring-projects/spring-ai","slug":"uri-must-not-be-null-or-empty","errorCode":null,"errorMessage":"URI must not be null or empty","messagePattern":"URI must not be null or empty","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java","lineNumber":726,"sourceCode":"\t\t */\n\t\tpublic T mimeType(String mimeType) {\n\t\t\tthis.mimeType = mimeType;\n\t\t\treturn (T) this;\n\t\t}\n\n\t\t/**\n\t\t * Validate the builder state.\n\t\t * @throws IllegalArgumentException if the builder state is invalid\n\t\t */\n\t\tprotected void validate() {\n\t\t\tif (this.method == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Method must not be null\");\n\t\t\t}\n\t\t\tif (this.bean == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Bean must not be null\");\n\t\t\t}\n\t\t\tif (this.uri == null || this.uri.isEmpty()) {\n\t\t\t\tthrow new IllegalArgumentException(\"URI must not be null or empty\");\n\t\t\t}\n\t\t\tif (this.uriTemplateManagerFactory == null) {\n\t\t\t\tthis.uriTemplateManagerFactory = new DefaultMcpUriTemplateManagerFactory();\n\t\t\t}\n\t\t\tif (this.mimeType == null) {\n\t\t\t\tthis.mimeType = \"text/plain\";\n\t\t\t}\n\n\t\t\tif (this.name == null) {\n\t\t\t\tthis.name = this.method.getName();\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Build the callback.\n\t\t * @return A new callback instance\n\t\t */\n\t\tpublic abstract R build();","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/mcp-annotations/src/main/java/org/springframework/ai/mcp/annotation/method/resource/AbstractMcpResourceMethodCallback.java#L708-L744","documentation":"Builder-state validation error thrown when the @McpResource uri attribute is null or empty when building an AbstractMcpResourceMethodCallback. The URI template is required to match client resource requests and extract URI variables.","triggerScenarios":"Programmatic builder usage omitting .uri(...), or an @McpResource annotation with an empty uri value propagated into the builder.","commonSituations":"Constructing callbacks manually without the uri; reading the annotation value with reflection and getting an empty string; copy-pasted annotation with blanked-out uri.","solutions":["Set a non-empty URI template: .uri(\"docs/{id}\") or fill in the @McpResource(uri = ...) value","Validate the annotation value before passing it to the builder","Follow URI template syntax with variables in braces if URI variables are used"],"exampleFix":"// before\nMcpSyncResourceMethodCallback.builder().bean(bean).method(m).uri(\"\").build();\n// after\nMcpSyncResourceMethodCallback.builder().bean(bean).method(m).uri(\"docs/{id}\").build();","handlingStrategy":"validation","validationCode":"if (uri == null || uri.isEmpty()) throw new IllegalStateException(\"@McpResource uri must be a non-empty URI template\");","typeGuard":"if (!(uri instanceof String u) || u.isBlank()) { throw new IllegalStateException(\"Missing or blank resource uri\"); }","tryCatchPattern":"try {\n    var cb = builder().bean(bean).method(method).uri(uri).build();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"URI must not be null\")) throw new IllegalStateException(\"Set a non-empty uri template on @McpResource\", e);\n    throw e;\n}","preventionTips":["Never leave the uri attribute of @McpResource empty","Validate annotation values with a startup test","Use explicit URI templates with {var} placeholders when URI variables are needed"],"tags":["mcp","java","builder","validation","uri-template"],"backgroundTag":"empty-required-field","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"}