didi/DoKit · error · ProtocolException
${method} does not support writing
Error message
${method} does not support writing What it means
Inside buildCall(), when doOutput is true the wrapper promotes GET to POST, but for any other method that does not permit a request body it throws ProtocolException(method + " does not support writing"). permitsRequestBody() only allows methods with bodies (POST/PUT/PATCH...), so e.g. HEAD/DELETE/TRACE with doOutput=true fails here.
Source
Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/aop/urlconnection/ObsoleteUrlFactory.java:558
.build();
}
@Override
public int getReadTimeout() {
return client.readTimeoutMillis();
}
private Call buildCall() throws IOException {
if (call != null) {
return call;
}
connected = true;
if (doOutput) {
if (method.equals("GET")) {
method = "POST";
} else if (!permitsRequestBody(method)) {
throw new ProtocolException(method + " does not support writing");
}
}
if (requestHeaders.get("User-Agent") == null) {
requestHeaders.add("User-Agent", defaultUserAgent());
}
OutputStreamRequestBody requestBody = null;
if (permitsRequestBody(method)) {
String contentType = requestHeaders.get("Content-Type");
if (contentType == null) {
contentType = "application/x-www-form-urlencoded";
requestHeaders.add("Content-Type", contentType);
}
boolean stream = fixedContentLength != -1L || chunkLength > 0;
long contentLength = -1L;View on GitHub (pinned to 626827cddb)
Solutions
- Only call setDoOutput(true) when you actually send a body with a body-permitting method.
- Set doOutput(false) (default) for DELETE/HEAD/OPTIONS requests.
- Move DELETE parameters into the query string or switch the endpoint to POST semantics if a body is required.
Example fix
// before
conn.setRequestMethod("DELETE");
conn.setDoOutput(true); // later -> DELETE does not support writing
// after
conn.setRequestMethod("DELETE");
// no setDoOutput; params in URL:
url += "?id=" + id; Defensive patterns
Strategy: validation
Validate before calling
if (needsBody) conn.setDoOutput(true); // else leave default false
Type guard
static boolean methodSupportsWriting(String m) {
return m.equals("GET") || m.equals("POST") || m.equals("PUT") || m.equals("PATCH");
} Prevention
- setDoOutput(true) only on body-carrying requests.
- For DELETE, put identifying data in the URL or switch to POST+override header.
When it happens
Trigger: setDoOutput(true) combined with setRequestMethod("HEAD"|"DELETE"|"TRACE"|"OPTIONS"), then triggering the connection via connect()/getOutputStream()/getInputStream().
Common situations: A generic request builder that always calls setDoOutput(true) 'to be safe', later used with a DELETE endpoint; REST clients migrating a POST endpoint to DELETE without dropping doOutput.
Related errors
- method does not support a request body: ${method}
- cannot write request body after response has been read
- 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/0fb7f112385e3217.
Report an issue: GitHub.