didi/DoKit · error · ProtocolException

method does not support a request body: ${method}

Error message

method does not support a request body: ${method}

What it means

getOutputStream() builds the OkHttp call and inspects its request body; when buildCall() produced no OutputStreamRequestBody (because the method does not permit a body, e.g. GET without the doOutput promotion or methods like DELETE/HEAD), it throws ProtocolException("method does not support a request body: " + method). Per the source, only doOutput=true turns GET into POST; other bodyless methods are not auto-promoted.

Source

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

            Response response = getResponse(false);
            if (response.code() >= HTTP_BAD_REQUEST) {
                Log.e("DoKit", "FileNotFoundException:" + url.toString());
                return ConvertUtils.string2InputStream("FileNotFoundException:" + url.toString(), "utf-8");
            }

            if (response.body() != null) {
                return response.body().byteStream();
            } else {
                return ConvertUtils.string2InputStream("response.body() is null:" + url.toString(), "utf-8");
            }

        }

        @Override
        public OutputStream getOutputStream() throws IOException {
            OutputStreamRequestBody requestBody = (OutputStreamRequestBody) buildCall().request().body();
            if (requestBody == null) {
                throw new ProtocolException("method does not support a request body: " + method);
            }

            if (requestBody instanceof StreamedRequestBody) {
                connect();
                networkInterceptor.proceed();
            }

            if (requestBody.closed) {
                throw new ProtocolException("cannot write request body after response has been read");
            }

            return requestBody.outputStream;
        }

        @Override
        public Permission getPermission() {
            URL url = getURL();
            String hostname = url.getHost();

View on GitHub (pinned to 626827cddb)

Solutions

  1. Call setDoOutput(true) and use a body-permitting method (POST/PUT/PATCH) before getOutputStream().
  2. For GET specifically, rely on the automatic GET->POST promotion by setting doOutput(true), or switch the method explicitly.
  3. Skip body writing entirely for HEAD/DELETE-style calls; send DELETE parameters in the URL if the server allows.

Example fix

// before
conn.setRequestMethod("DELETE");
conn.setDoOutput(true);
conn.getOutputStream().write(body); // ProtocolException

// after
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.getOutputStream().write(body);
Defensive patterns

Strategy: validation

Validate before calling

static boolean permitsBody(String m) {
  return m.equals("POST") || m.equals("PUT") || m.equals("PATCH");
}
if (permitsBody(method)) { conn.setDoOutput(true); os = conn.getOutputStream(); }

Type guard

static boolean canWriteBody(HttpURLConnection c) {
  String m = c.getRequestMethod();
  return c.getDoOutput() && (m.equals("GET") || permitsBody(m)); // GET auto-promotes to POST
}

Prevention

When it happens

Trigger: Calling getOutputStream() after setRequestMethod("HEAD") or "DELETE" with setDoOutput(true); calling getOutputStream() without setDoOutput(true) on a method that permits no body.

Common situations: Generic HTTP helper that always writes a body but lets callers pick arbitrary methods; switching a request from POST to DELETE/HEAD without removing the body-writing branch.

Related errors


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