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

  1. Ensure the agentUrl uses http:// or https:// scheme
  2. Correct any protocol typos in the agentUrl value
  3. 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

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


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/2220c1fdd5f7b601. Report an issue: GitHub.