spring-projects/spring-ai · error · SecurityException
Unsupported URL protocol:
Error message
Unsupported URL protocol:
What it means
Thrown when Media data is a java.net.URL whose protocol is not http or https. mapMediaToContentBlock enforces an allowlist of HTTP/HTTPS to prevent SSRF-style access via file:, ftp:, jar:, etc. The protocol is included in the message.
Source
Thrown at models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java:563
catch (SecurityException | RestClientException e) {
throw new RuntimeException("Failed to read media data from URL: " + text, e);
}
}
else {
throw new SecurityException("URL is not valid under strict validation rules: " + text);
}
}
else {
// Assume it's base64-encoded image data
sourceBuilder.bytes(SdkBytes.fromByteArray(Base64.getDecoder().decode(text)));
}
}
else if (media.getData() instanceof URL url) {
try {
String protocol = url.getProtocol();
if (!"http".equalsIgnoreCase(protocol) && !"https".equalsIgnoreCase(protocol)) {
throw new SecurityException("Unsupported URL protocol: " + protocol);
}
byte[] bytes = this.mediaFetcher.fetch(url.toURI());
sourceBuilder.bytes(SdkBytes.fromByteArrayUnsafe(bytes)).build();
}
catch (SecurityException | RestClientException | URISyntaxException e) {
throw new IllegalArgumentException("Failed to read media data from URL: " + url, e);
}
}
else {
throw new IllegalArgumentException("Invalid Image content type: " + media.getData().getClass());
}
return ContentBlock.fromImage(ImageBlock.builder()
.source(sourceBuilder.build())
.format(BedrockMediaFormat.getImageFormat(mimeType))
.build());
}
else if (BedrockMediaFormat.isSupportedDocumentFormat(mimeType)) { // DocumentView on GitHub (pinned to 98a7beda4f)
Solutions
- Switch to an http/https URL for the media resource.
- Load the local resource yourself and pass byte[]/base64 data instead of a URL.
- Upload the asset to an accessible HTTP endpoint (e.g. S3 with public/signed URL over https).
- Check url.getProtocol() before constructing Media to fail fast with a clear message.
Example fix
// before
new Media(MimeTypeUtils.IMAGE_PNG, new URL("file:///img/cat.png"));
// after
byte[] bytes = Files.readAllBytes(Path.of("/img/cat.png"));
new Media(MimeTypeUtils.IMAGE_PNG, bytes); Defensive patterns
Strategy: type-guard
Validate before calling
String proto = url.getProtocol();
if (!"http".equalsIgnoreCase(proto) && !"https".equalsIgnoreCase(proto)) {
throw new IllegalArgumentException("Only http/https media URLs supported, got: " + proto);
} Type guard
boolean isHttpUrl(URL url) {
return url != null && ("http".equalsIgnoreCase(url.getProtocol()) || "https".equalsIgnoreCase(url.getProtocol()));
} Try / catch
try {
model.call(prompt);
} catch (IllegalArgumentException e) {
if (e.getCause() instanceof SecurityException se && se.getMessage().contains("Unsupported URL protocol")) {
// load bytes locally and resend with byte[] data
} else throw e;
} Prevention
- Assert protocol is http/https before constructing Media with a URL
- Use Files.readAllBytes for local assets instead of file:// URLs
- Host assets on https endpoints (e.g. S3) when remote access is needed
When it happens
Trigger: Constructing Media with new URL("file:///path/img.png"), ftp://, or any non-HTTP(S) URL and sending it to the Bedrock model. Also triggered when the URL itself is fine but the subsequent fetch/URI conversion throws SecurityException, RestClientException, or URISyntaxException, which are rewrapped (see error 303).
Common situations: Developers building media from local files or classpath resources using file:// URLs; test fixtures using ftp servers; migrating code from other AI libraries that accepted file URLs.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- URL is not valid under strict validation rules:
- Media URL response exceeds maximum allowed size of bytes
- Failed to read media data from URL:
- Host '' is not in the allowed hosts list. Configure MediaFet
- Media URL response exceeds maximum allowed size of bytes:
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/b321b30ff53f23a1.
Report an issue: GitHub.