{"record":{"id":"44f2e24e94008bec","repo":"spring-projects/spring-ai","slug":"java-net-urisyntaxexception","errorCode":null,"errorMessage":"java.net.URISyntaxException","messagePattern":"java\\.net\\.URISyntaxException","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java","lineNumber":176,"sourceCode":"\t\tprivate @Nullable String text;\n\n\t\t@Override\n\t\tpublic PromptUserSpec media(Media... media) {\n\t\t\tAssert.notNull(media, \"media cannot be null\");\n\t\t\tAssert.noNullElements(media, \"media cannot contain null elements\");\n\t\t\tthis.media.addAll(Arrays.asList(media));\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic PromptUserSpec media(MimeType mimeType, URL url) {\n\t\t\tAssert.notNull(mimeType, \"mimeType cannot be null\");\n\t\t\tAssert.notNull(url, \"url cannot be null\");\n\t\t\ttry {\n\t\t\t\tthis.media.add(Media.builder().mimeType(mimeType).data(url.toURI()).build());\n\t\t\t}\n\t\t\tcatch (URISyntaxException e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic PromptUserSpec media(MimeType mimeType, Resource resource) {\n\t\t\tAssert.notNull(mimeType, \"mimeType cannot be null\");\n\t\t\tAssert.notNull(resource, \"resource cannot be null\");\n\t\t\tthis.media.add(Media.builder().mimeType(mimeType).data(resource).build());\n\t\t\treturn this;\n\t\t}\n\n\t\t@Override\n\t\tpublic PromptUserSpec text(String text) {\n\t\t\tAssert.hasText(text, \"text cannot be null or empty\");\n\t\t\tthis.text = text;\n\t\t\treturn this;\n\t\t}","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java#L158-L194","documentation":"DefaultChatClient's PromptUserSpec.media(MimeType, URL) converts the URL to a URI and wraps any URISyntaxException in a RuntimeException. A URL that is not a valid absolute, structured URI (e.g. has illegal characters or spaces) cannot be converted, so media registration fails.","triggerScenarios":"Calling .user(u -> u.media(mimeType, new URL(\"...\"))) with a URL containing unescaped spaces/illegal characters, a relative URL like new URL(\"foo/bar\"), or a malformed protocol string passed to the URL constructor.","commonSituations":"Interpolating unencoded file names or query strings into the URL; using file: URLs built by string concatenation; URLs read from user input or config that were never encoded.","solutions":["URL-encode the string before constructing the URL (URLEncoder / URI multi-arg constructor)","Build via new URI(scheme, authority, path, query, fragment) which escapes components","Validate the URL format before passing it to media()","Use the media(MimeType, Resource) overload with a proper Resource instead of a URL"],"exampleFix":"// before\n.user(u -> u.media(mimeType, new URL(\"https://x.com/my file.png\"))) // URISyntaxException\n// after\nURI uri = new URI(\"https\", \"x.com\", \"/my file.png\", null);\n.user(u -> u.media(mimeType, uri.toURL()));","handlingStrategy":"try-catch","validationCode":"try { new URI(url.toString()); } catch (URISyntaxException e) { throw new IllegalArgumentException(\"Invalid media URL: \" + url, e); }","typeGuard":"static Optional<URI> safeUri(URL url) { try { return Optional.of(url.toURI()); } catch (URISyntaxException e) { return Optional.empty(); } }","tryCatchPattern":"try { builder.user(u -> u.media(mime, url)); } catch (RuntimeException e) { if (e.getCause() instanceof URISyntaxException) { /* encode URL and retry */ } throw e; }","preventionTips":["Build URLs with the multi-argument URI constructor so components are escaped","URL-encode file names and query params before creating URLs","Prefer the media(MimeType, Resource) overload for local/classpath content"],"tags":["java","chat-client","url","media"],"backgroundTag":"invalid-url-format","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"}