didi/DoKit · error · IllegalStateException

Negative size: " + bitmap

Error message

Negative size: " + bitmap

What it means

Utils.getBitmapBytes(Bitmap) computes a bitmap's byte size — getByteCount() on API 12+, otherwise rowBytes * height — and throws IllegalStateException if the result is negative. A negative value means the arithmetic overflowed int (rowBytes * height exceeded 2^31) or the bitmap is in an invalid state; the library treats it as an unrecoverable accounting error because cache sizing and stats depend on it.

Source

Thrown at Android/dokit/src/main/java/com/didichuxing/doraemonkit/picasso/Utils.java:116

    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  */
  private static final int WEBP_FILE_HEADER_SIZE = 12;
  private static final String WEBP_FILE_HEADER_RIFF = "RIFF";
  private static final String WEBP_FILE_HEADER_WEBP = "WEBP";

  private Utils() {
    // No instances.
  }

  static int getBitmapBytes(Bitmap bitmap) {
    int result;
    if (SDK_INT >= HONEYCOMB_MR1) {
      result = BitmapHoneycombMR1.getByteCount(bitmap);
    } else {
      result = bitmap.getRowBytes() * bitmap.getHeight();
    }
    if (result < 0) {
      throw new IllegalStateException("Negative size: " + bitmap);
    }
    return result;
  }

  static <T> T checkNotNull(T value, String message) {
    if (value == null) {
      throw new NullPointerException(message);
    }
    return value;
  }

  static void checkNotMain() {
    if (isMain()) {
      throw new IllegalStateException("Method call should not happen from the main thread.");
    }
  }

  static void checkMain() {

View on GitHub (pinned to 626827cddb)

Solutions

  1. Downsample large sources: use .resize(targetW, targetH).onlyScaleDown() on the request, or BitmapFactory.Options.inSampleSize for manual decoding.
  2. Target view-sized dimensions rather than native image dimensions for all loads.
  3. If it reproduces only on ancient devices, gate huge-image features by device memory class (ActivityManager.getMemoryClass()).

Example fix

// before
picasso.load(hugePhotoUrl).into(imageView); // full-res decode, overflows byte count

// after
picasso.load(hugePhotoUrl)
    .resize(imageView.getMaxWidth(), imageView.getMaxHeight())
    .onlyScaleDown()
    .centerInside()
    .into(imageView);
Defensive patterns

Strategy: validation

Validate before calling

// Bound the decode size before loading
int maxDim = context.getResources().getDisplayMetrics().widthPixels;
picasso.load(url).resize(maxDim, maxDim).onlyScaleDown().centerInside().into(iv);

Try / catch

Not applicable — the throw indicates corrupted size accounting; prevent by bounding bitmap dimensions.

Prevention

When it happens

Trigger: On pre-Honeycomb MR1 devices, loading or creating a bitmap whose rowBytes * height overflows Integer.MAX_VALUE (over ~2GB, e.g. decoding a huge photo without downsampling); extremely rarely, a bitmap whose dimensions report nonsense values.

Common situations: Decoding a very large camera image at full resolution into memory with no inSampleSize; old-device (API < 12) code paths in legacy builds; OOM-adjacent situations where a bitmap larger than 2GB is attempted.

Related errors


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