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

  1. Return the input request from transformRequest when no rewrite applies
  2. Audit every return path of the transformer named in the message
  3. 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

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.