didi/DoKit · error · ProtocolException

Expected one of " + METHODS + " but was " + method

Error message

Expected one of " + METHODS + " but was " + method

What it means

setRequestMethod() validates the method against a fixed METHODS set (the HTTP methods OkHttp's HttpURLConnection shim supports: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE) and throws ProtocolException("Expected one of " + METHODS + " but was " + method) for anything else. Custom methods like PATCH or PROPFIND are not accepted.

Source

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

        @Override
        public void addRequestProperty(String field, String value) {
            if (connected) {
                throw new IllegalStateException("Cannot add request property after connection is made");
            }
            if (field == null) {
                throw new NullPointerException("field == null");
            }
            if (value == null) {
                return;
            }

            requestHeaders.add(field, value);
        }

        @Override
        public void setRequestMethod(String method) throws ProtocolException {
            if (!METHODS.contains(method)) {
                throw new ProtocolException("Expected one of " + METHODS + " but was " + method);
            }
            this.method = method;
        }

        @Override
        public void setFixedLengthStreamingMode(int contentLength) {
            setFixedLengthStreamingMode((long) contentLength);
        }

        @Override
        public void setFixedLengthStreamingMode(long contentLength) {
            if (super.connected) throw new IllegalStateException("Already connected");
            if (chunkLength > 0) throw new IllegalStateException("Already in chunked mode");
            if (contentLength < 0) throw new IllegalArgumentException("contentLength < 0");
            this.fixedContentLength = contentLength;
            super.fixedContentLength = (int) Math.min(contentLength, Integer.MAX_VALUE);
        }

View on GitHub (pinned to 626827cddb)

Solutions

  1. For PATCH specifically, send POST with an X-HTTP-Method-Override: PATCH header, or use OkHttp's Request.Builder.method("PATCH", body) directly which supports arbitrary methods.
  2. Verify the method string: exact uppercase, no surrounding whitespace, matches one of GET/POST/HEAD/OPTIONS/PUT/DELETE/TRACE.
  3. Constant-define method names instead of building them dynamically.

Example fix

// before
conn.setRequestMethod("PATCH"); // ProtocolException

// after
conn.setRequestMethod("POST");
conn.setRequestProperty("X-HTTP-Method-Override", "PATCH");
// or use OkHttp directly:
// Request req = new Request.Builder().url(u).method("PATCH", body).build();
Defensive patterns

Strategy: validation

Validate before calling

Set<String> OK = new HashSet<>(Arrays.asList("GET","POST","HEAD","OPTIONS","PUT","DELETE","TRACE"));
String m = method.trim().toUpperCase(Locale.US);
if (!OK.contains(m)) { /* use OkHttp Request.Builder or POST + X-HTTP-Method-Override */ }

Type guard

static boolean isSupportedUrlConnectionMethod(String m) {
  return Arrays.asList("GET","POST","HEAD","OPTIONS","PUT","DELETE","TRACE").contains(m);
}

Prevention

When it happens

Trigger: setRequestMethod("PATCH") — the classic case, since PATCH is not in the set; typos like "post" (lowercase) or "GET " (trailing space); custom WebDAV methods.

Common situations: Migrating a POST endpoint to PATCH; copy-pasted method strings with wrong case; REST wrappers exposing arbitrary verbs.

Related errors


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