spring-projects/spring-ai · error · RuntimeException
java.net.URISyntaxException
Error message
java.net.URISyntaxException
What it means
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.
Source
Thrown at spring-ai-client-chat/src/main/java/org/springframework/ai/chat/client/DefaultChatClient.java:176
private @Nullable String text;
@Override
public PromptUserSpec media(Media... media) {
Assert.notNull(media, "media cannot be null");
Assert.noNullElements(media, "media cannot contain null elements");
this.media.addAll(Arrays.asList(media));
return this;
}
@Override
public PromptUserSpec media(MimeType mimeType, URL url) {
Assert.notNull(mimeType, "mimeType cannot be null");
Assert.notNull(url, "url cannot be null");
try {
this.media.add(Media.builder().mimeType(mimeType).data(url.toURI()).build());
}
catch (URISyntaxException e) {
throw new RuntimeException(e);
}
return this;
}
@Override
public PromptUserSpec media(MimeType mimeType, Resource resource) {
Assert.notNull(mimeType, "mimeType cannot be null");
Assert.notNull(resource, "resource cannot be null");
this.media.add(Media.builder().mimeType(mimeType).data(resource).build());
return this;
}
@Override
public PromptUserSpec text(String text) {
Assert.hasText(text, "text cannot be null or empty");
this.text = text;
return this;
}View on GitHub (pinned to 98a7beda4f)
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
Example fix
// before
.user(u -> u.media(mimeType, new URL("https://x.com/my file.png"))) // URISyntaxException
// after
URI uri = new URI("https", "x.com", "/my file.png", null);
.user(u -> u.media(mimeType, uri.toURL())); Defensive patterns
Strategy: try-catch
Validate before calling
try { new URI(url.toString()); } catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid media URL: " + url, e); } Type guard
static Optional<URI> safeUri(URL url) { try { return Optional.of(url.toURI()); } catch (URISyntaxException e) { return Optional.empty(); } } Try / catch
try { builder.user(u -> u.media(mime, url)); } catch (RuntimeException e) { if (e.getCause() instanceof URISyntaxException) { /* encode URL and retry */ } throw e; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Unsupported media data type: . Expected byte[] or String.
- java.io.IOException
- java.io.IOException
- Failed to create SSE transport for connection '<connectionNa
- Method must have exactly 1 parameter (List<McpSchema.Resourc
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/44f2e24e94008bec.
Report an issue: GitHub.