EEltaCrew
Home › Blog

A crash from one line of image downsampling: inSampleSize starts at 0

Published 2026-10-13Measured 2026-10-13About 3 min readelta · EltaCrew

To save memory, we changed the document thumbnails in our QR scanner app to load downsampled. In the next version, the app closed every time the document list opened. The cause was that BitmapFactory.Options.inSampleSize defaults to 0. The code we changed, the crash data, the fix, and how we checked for the same mistake elsewhere.

It started with a memory recommendation

On October 10, after looking at Play Console's memory-related recommendations, we went through our live apps and fixed places that decoded images at full size. The document list in our QR scanner app was one of them.

Each row in the document list has a small thumbnail. That thumbnail file turned out to be the original JPEG of the scanned page. To draw one small row, the app was loading the full-resolution image into memory.

The code we changed

We changed it to read the size first, then halve the image until the short side would drop below 320px.

BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, bounds);

BitmapFactory.Options opts = new BitmapFactory.Options();
int minDim = Math.min(bounds.outWidth, bounds.outHeight);
while (minDim / (opts.inSampleSize * 2) >= 320) opts.inSampleSize *= 2;
Bitmap bmp = BitmapFactory.decodeFile(path, opts);

The build passed, and the change shipped with other fixes in version 1.1.25 on October 11.

The app closed every time the document list opened

The next day, a new crash showed up in Crashlytics.

java.lang.ArithmeticException: divide by zero
    at ...ui.document.DocumentAdapter.lambda$onBindViewHolder$1

Over the 7 days up to 9 AM on October 13 (KST), there were 27 events from 4 users, all on 1.1.25. If there was even one document with a thumbnail, the app closed the moment the document list opened. Thumbnail decoding runs on a background thread, and nothing there caught the exception, so the whole app went down.

The cause: the default is 0

In options created with new BitmapFactory.Options(), inSampleSize is 0. The decoder treats any value of 1 or less as 1, so a 0 is harmless when you only decode. That's why you normally never notice it's 0.

The problem was using that value directly in arithmetic. The first pass of the loop computes minDim / (0 * 2), which is minDim / 0.

The example in the Android documentation starts its calculation with a local variable, int inSampleSize = 1;. Our code used the options field as the loop variable directly and left out the line that starts it at 1.

Why testing didn't catch it is also clear. It was a change where "the screen stays the same and only the internals change", so we looked only at the build passing and shipped it without actually opening a document list that had thumbnails.

The fix

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
int minDim = Math.min(bounds.outWidth, bounds.outHeight);
while (minDim > 0 && minDim / (opts.inSampleSize * 2) >= 320) opts.inSampleSize *= 2;

We submitted 1.1.26 on October 13. This time we installed the release build we were submitting on a real device, created a document from a gallery photo, and checked that the thumbnail appeared in the document list.

Is the same mistake anywhere else?

Our other apps also have downsampling code, so we searched all our live app code for inSampleSize * 2.

There was only one place with the problem.

Summary

The app in this post is QR Code Scanner & Reader (Google Play).

AndroidBitmapFactoryCrashlyticsMemoryCrashes

Related

Why our lottery ticket QR scanner showed zero successes: a path you don't log looks like a failureIn our lottery app's weekly report, 19 people had opened the QR screen and GA4 showed zero successful scans. The scanner wasn't broken. The path that real ticket QR codes took had no logging at all. How we found the measurement gap, what four similar apps do, why we switched to the bundled scanning engine, and the numbers one week after the fix.Tapping the logo in the map's corner crashed the app: Naver Map SDK and the AppCompat themeFour "You need to use a Theme.AppCompat theme" crashes showed up in Crashlytics for our lottery store map app. They came not from users but from the Play pre-launch report's test robot tapping the NAVER logo in the bottom-left corner of the map. The cause, a fix that wraps only the map instead of changing the whole app theme, and a second problem that appeared in dark mode.Requesting ads before the SDK finishes initializing: why the same crash came back three times after we added a guardAfter we first fixed the "MobileAds.initialize must be called" crash in our live apps, the same crash came back three more times in different shapes. We had a guard that waited for initialization to finish, but a flag set at the start, a flag set on consent alone, and new ad slots that skipped the guard all left gaps. The cause of each case and the results of checking all 23 apps.