didi/DoKit · error · NullPointerException

Transformation " + transformation.key() + " returned null af

Error message

Transformation " + transformation.key() + " returned null after " + i + " previous transformation(s).\n\nTransformation list:\n" + ...

What it means

applyCustomTransformations requires every Transformation.transform() to return a non-null Bitmap. If one returns null, Picasso posts a NullPointerException whose message lists the failing transformation's key, its position in the chain, and the full transformation list, then aborts the request. The detailed message exists precisely to identify which of several chained transformations misbehaved.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/BitmapHunter.java:452

                "Transformation " + transformation.key() + " crashed with exception.", e);
          }
        });
        return null;
      }

      if (newResult == null) {
        final StringBuilder builder = new StringBuilder() //
            .append("Transformation ")
            .append(transformation.key())
            .append(" returned null after ")
            .append(i)
            .append(" previous transformation(s).\n\nTransformation list:\n");
        for (Transformation t : transformations) {
          builder.append(t.key()).append('\n');
        }
        DokitPicasso.HANDLER.post(new Runnable() {
          @Override public void run() {
            throw new NullPointerException(builder.toString());
          }
        });
        return null;
      }

      if (newResult == result && result.isRecycled()) {
        DokitPicasso.HANDLER.post(new Runnable() {
          @Override public void run() {
            throw new IllegalStateException("Transformation "
                + transformation.key()
                + " returned input Bitmap but recycled it.");
          }
        });
        return null;
      }

      // If the transformation returned a new bitmap ensure they recycled the original.
      if (newResult != result && !result.isRecycled()) {

View on GitHub (pinned to 626827cddb)

Solutions

  1. Match the message's key to your Transformation class and make it return the input bitmap unchanged instead of null
  2. Treat the contract as: transform must always return a usable Bitmap — validate before mutating, never return null
  3. If you cannot produce output, return src (identity) so the request completes
  4. Check chained transformations individually to find the null-returner named in the message

Example fix

// before
@Override public Bitmap transform(Bitmap src) {
  if (src.getWidth() < 10) return null;
  return scale(src);
}

// after
@Override public Bitmap transform(Bitmap src) {
  if (src.getWidth() < 10 || src.getHeight() < 10) return src; // identity, never null
  return scale(src);
}
Defensive patterns

Strategy: validation

Validate before calling

// Enforce the contract in a decorator:
final class NonNullTransformation implements Transformation {
  private final Transformation delegate;
  NonNullTransformation(Transformation d) { this.delegate = d; }
  @Override public Bitmap transform(Bitmap src) {
    Bitmap out = delegate.transform(src);
    return out != null ? out : src; // never null
  }
  @Override public String key() { return delegate.key() + "!nonnull"; }
}

Try / catch

// Thrown on the main thread by Picasso, not at the load call site — catch inside the
// transformation instead:
@Override public Bitmap transform(Bitmap src) {
  try {
    Bitmap out = doScale(src);
    return out != null ? out : src;
  } catch (RuntimeException e) {
    return src;
  }
}

Prevention

When it happens

Trigger: A transform whose code path returns null (e.g. early-return on invalid input, third-party SDK returning null); chaining transformations where an earlier one recycles the bitmap and a later one returns null after createBitmap fails; Kotlin transform with an implicit null from a nullable helper.

Common situations: Defensive 'return null on bad input' coding style inside transformations; copy-pasted transformations from code that assumed Picasso tolerates null.

Related errors


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