conductor-oss/conductor · error · NonRetryableException
agentUrl must use http or https, got: {scheme}
Error message
agentUrl must use http or https, got: {scheme} What it means
Thrown by A2AService.validateAgentUrl() when the URL uses a scheme other than http or https (e.g. file://, ftp://, gopher://). This is part of the SSRF protection layer and is a NonRetryableException (no retry, FAILED_WITH_TERMINAL_ERROR).
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/a2a/A2AService.java:440
}
/**
* Guards against SSRF: rejects URLs whose hostname resolves to an RFC-1918 address, loopback,
* link-local (169.254.x.x — AWS/GCP/Azure metadata), or any non-http(s) scheme.
*
* <p>Note: DNS resolution is performed once here. A sufficiently hostile DNS server could
* rebind the name to a private IP after this check (TOCTOU). For stronger protection, deploy
* behind a network-layer firewall that blocks egress to private ranges.
*/
public void validateAgentUrl(String rawUrl) {
if (rawUrl == null || rawUrl.isBlank()) {
throw new NonRetryableException("agentUrl must not be blank");
}
try {
URL url = new URL(rawUrl.trim());
String scheme = url.getProtocol();
if (!"http".equals(scheme) && !"https".equals(scheme)) {
throw new NonRetryableException("agentUrl must use http or https, got: " + scheme);
}
String host = url.getHost();
InetAddress[] addresses = InetAddress.getAllByName(host);
for (InetAddress addr : addresses) {
// Cloud metadata endpoints are blocked even when private networks are allowed.
if (isMetadataAddress(addr)) {
A2AMetrics.ssrfBlocked();
throw new NonRetryableException(
"agentUrl resolves to a cloud metadata address — SSRF blocked: "
+ addr.getHostAddress());
}
if (allowPrivateNetwork) {
continue;
}
if (addr.isLoopbackAddress()
|| addr.isSiteLocalAddress()
|| addr.isLinkLocalAddress()
|| addr.isAnyLocalAddress()View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Ensure the agentUrl uses http:// or https:// scheme
- Correct any protocol typos in the agentUrl value
- If testing locally, use http://localhost:port (note: localhost may also be blocked by SSRF rules unless allow-private-network is enabled)
Example fix
// before
{"agentUrl": "file:///path/to/agent"}
// after
{"agentUrl": "https://my-agent.example.com"} Defensive patterns
Strategy: validation
Validate before calling
// Validate URL scheme before the A2A call
try {
URL url = new URL(agentUrl.trim());
if (!"http".equals(url.getProtocol()) && !"https".equals(url.getProtocol())) {
throw new IllegalArgumentException("agentUrl must use http or https");
}
} catch (MalformedURLException e) {
throw new IllegalArgumentException("Invalid agentUrl: " + agentUrl, e);
} Type guard
public boolean isHttpOrHttpsUrl(String url) {
if (url == null || url.isBlank()) return false;
try {
String scheme = new URL(url.trim()).getProtocol();
return "http".equals(scheme) || "https".equals(scheme);
} catch (MalformedURLException e) {
return false;
}
} Try / catch
try {
a2aService.validateAgentUrl(agentUrl);
} catch (NonRetryableException e) {
if (e.getMessage().contains("must use http or https")) {
log.error("agentUrl has invalid scheme: {}", e.getMessage());
}
throw e;
} Prevention
- Always use http:// or https:// prefix in agentUrl
- Validate URLs on the client/workflow side before passing to A2A tasks
- Sanitize any user-provided URLs to reject non-HTTP schemes
When it happens
Trigger: The agentUrl string parses as a valid URL but the protocol/scheme is not 'http' or 'https'. For example: 'file:///etc/passwd', 'ftp://server/agent', 'gopher://internal-service'.
Common situations: The agentUrl was mistyped or contains a protocol prefix error. A malicious or misconfigured input attempts to use a non-HTTP protocol. The URL was constructed by string concatenation that accidentally produced a wrong scheme.
Related errors
- agentUrl resolves to a cloud metadata address — SSRF blocked
- agentUrl resolves to a private/reserved address — SSRF block
- agentUrl must not be blank
- agentUrl is not a valid URL: {rawUrl} — {message}
- Access denied: path matches blocked prefix '{prefix}'
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/2220c1fdd5f7b601.
Report an issue: GitHub.