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
- Call setDoOutput(true) and use a body-permitting method (POST/PUT/PATCH) before getOutputStream().
- For GET specifically, rely on the automatic GET->POST promotion by setting doOutput(true), or switch the method explicitly.
- 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
- Only request an OutputStream when the method carries a body.
- Remember GET+doOutput is silently promoted to POST; other bodyless methods are not.
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
- cannot write request body after response has been read
- ${method} does not support writing
- Cannot access request header fields after connection is set
- This protocol does not support input
- Cannot set request property after connection is made
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/510381b5af38a572.
Report an issue: GitHub.