didi/DoKit · error · IllegalStateException
Request transformer <requestTransformer.getClass().getCanoni
Error message
Request transformer <requestTransformer.getClass().getCanonicalName()> returned null for <request>
What it means
Every request passes through the configured RequestTransformer (identity by default) before hunting. transformRequest() enforces that the transformer returns a non-null Request; null triggers IllegalStateException naming the transformer class and the original request. The transform API is 'return a possibly-modified Request', never null — a null return would NPE later in the pipeline, so it is rejected at the boundary.
Source
Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/DokitPicasso.java:458
cache.clear();
cleanupThread.shutdown();
stats.shutdown();
dispatcher.shutdown();
for (DeferredRequestCreator deferredRequestCreator : targetToDeferredRequestCreator.values()) {
deferredRequestCreator.cancel();
}
targetToDeferredRequestCreator.clear();
shutdown = true;
}
List<RequestHandler> getRequestHandlers() {
return requestHandlers;
}
Request transformRequest(Request request) {
Request transformed = requestTransformer.transformRequest(request);
if (transformed == null) {
throw new IllegalStateException("Request transformer "
+ requestTransformer.getClass().getCanonicalName()
+ " returned null for "
+ request);
}
return transformed;
}
void defer(ImageView view, DeferredRequestCreator request) {
targetToDeferredRequestCreator.put(view, request);
}
void enqueueAndSubmit(Action action) {
Object target = action.getTarget();
if (target != null && targetToAction.get(target) != action) {
// This will also check we are on the main thread.
cancelExistingRequest(target);
targetToAction.put(target, action);
}View on GitHub (pinned to 626827cddb)
Solutions
- Return the input request from transformRequest when no rewrite applies
- Audit every return path of the transformer named in the message
- In Kotlin, declare the return type as non-nullable Request
Example fix
// before
new DokitPicasso.Builder(context)
.requestTransformer(new RequestTransformer() {
@Override public Request transformRequest(Request request) {
if (request.uri != null && request.uri.getHost() != null) return request;
return null; // -> IllegalStateException
}
}).build();
// after
@Override public Request transformRequest(Request request) {
return request.buildUpon().build(); // always non-null; modify only when needed
} Defensive patterns
Strategy: validation
Validate before calling
// Ensure every branch returns non-null; default to the input request:
RequestTransformer safe = new RequestTransformer() {
@Override public Request transformRequest(Request request) {
if (request.uri == null) return request;
if (!request.uri.isRelative()) return request;
return request.buildUpon().uri(Uri.parse("https://cdn.example.com/" + request.uri)).build();
}
}; Try / catch
// transformRequest runs synchronously inside submit(), so a caller-side guard works:
// just guarantee non-null in the transformer. If wrapping third-party transformers:
Request transformSafe(Request in, RequestTransformer t) {
Request out = t.transformRequest(in);
return out != null ? out : in;
} Prevention
- transformRequest must return a Request on every path — 'no change' means return the input
- Kotlin: declare override fun transformRequest(request: Request): Request (non-nullable)
- Unit-test the transformer with http, https, file, and resource-id requests
When it happens
Trigger: A custom RequestTransformer (set via Builder.requestTransformer(...)) whose transformRequest returns null on a code path — e.g. when it does not recognize the URI, or when Kotlin nullable returns leak through; a transformer ported from a version that used null to signal 'skip'.
Common situations: Debug-only transformers that rewrite URLs and return null in release builds; conditional rewrite logic missing a default return input branch.
Related errors
AI-assisted analysis of didi/DoKit@626827cddb (2026-08-14).
Data as JSON: /api/errors/c243e9381cb5f511.
Report an issue: GitHub.