didi/DoKit · error · IllegalArgumentException

Unexpected protocol: ${protocol}

Error message

Unexpected protocol: ${protocol}

What it means

ObsoleteUrlFactory.open(URL, Proxy) inspects url.getProtocol() and only knows how to map "http" and "https" onto OkHttp connections; any other scheme falls through to IllegalArgumentException("Unexpected protocol: " + protocol). This factory is DoKit's replacement for okhttp3.JavaNetUrlFactory so that URL.openConnection() traffic is routed through OkHttp for capture.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java:158

     */
    @Override
    public ObsoleteUrlFactory clone() {
        return new ObsoleteUrlFactory(client);
    }

    public HttpURLConnection open(URL url) {
        return open(url, client.proxy());
    }

    HttpURLConnection open(URL url, @Nullable Proxy proxy) {
        String protocol = url.getProtocol();
        OkHttpClient copy = client.newBuilder()
                .proxy(proxy)
                .build();

        if (protocol.equals("http")) return new OkHttpURLConnection(url, copy);
        if (protocol.equals("https")) return new OkHttpsURLConnection(url, copy);
        throw new IllegalArgumentException("Unexpected protocol: " + protocol);
    }

    /**
     * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}.
     *
     * <p>This code configures OkHttp to handle all HTTP and HTTPS connections
     * created with {@link URL#openConnection()}: <pre>   {@code
     *
     *   OkHttpClient okHttpClient = new OkHttpClient();
     *   URL.setURLStreamHandlerFactory(new ObsoleteUrlFactory(okHttpClient));
     * }</pre>
     */
    @Override
    public URLStreamHandler createURLStreamHandler(final String protocol) {
        if (!protocol.equals("http") && !protocol.equals("https")) return null;

        return new URLStreamHandler() {
            @Override

View on GitHub (pinned to 626827cddb)

Solutions

  1. Avoid URL.openConnection() for non-http(s) schemes: use new FileInputStream(path) for files, or ClassLoader.getResourceAsStream() for classpath resources.
  2. Normalize the URL to http/https before openConnection() when the resource is actually served over HTTP.
  3. If you control the factory install, only install it for http/https or unset DoKit's URL-connection interception when non-HTTP protocols are needed.

Example fix

// before
InputStream in = new URL("file:///data/local/tmp/a.txt").openConnection().getInputStream();

// after
InputStream in = new FileInputStream("/data/local/tmp/a.txt");
Defensive patterns

Strategy: validation

Validate before calling

String p = url.getProtocol();
if (!("http".equals(p) || "https".equals(p))) {
  throw new UnsupportedOperationException("unsupported scheme: " + p);
}

Type guard

static boolean isHttpUrl(URL u) {
  String p = u.getProtocol();
  return "http".equals(p) || "https".equals(p);
}

Try / catch

try { conn = factory.open(url); } catch (IllegalArgumentException e) { if (!isHttpUrl(url)) useNativeHandler(url); else throw e; }

Prevention

When it happens

Trigger: Calling url.openConnection() (or open()) on a URL with a scheme like file:, ftp:, jar:, or a custom scheme while URL.setURLStreamHandlerFactory has installed this factory globally.

Common situations: DoKit installs the factory app-wide; later code opens a file: or jar: URL (very common for classpath resources, WebView assets, or local file access) and crashes because the factory intercepts every protocol.

Related errors


AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14). Data as JSON: /api/errors/58870ec1bf2de22d. Report an issue: GitHub.