devtestudinidae

DevTestudinidae

Independent developer writing practical notes on AI-assisted development, automation, troubleshooting, and small web tools.

Richchecker KR: repairing a photo upload path that failed on Android Chrome

한국어: Richchecker KR 안드로이드 사진 업로드 오류 개선

I shipped a revised photo upload path in Richchecker KR on November 13, 2026. Some Android Chrome visits had recorded an error before photo analysis could start. I removed the full-file Base64 conversion and added checks for unsupported or oversized photos. The implementation is in PR #1 and PR #2.

The failure in the original measurements

I examined the app’s November 12 GA4 events by browser and error stage.

Recorded event Events Measured users
Upload started 14 5
Upload error (file_read) 8 3
Analysis completed 6 3

All eight file_read errors came from mobile Android Chrome in South Korea. That browser segment had nine starts, eight errors and one completed analysis. These are aggregated event counts, however, and cannot be matched to individual upload attempts. Dividing eight by nine would produce an unsupported failure rate. The investigation notes keep the exact scope visible.

Loading the file without another full-file string

The previous picker used FileReader.readAsDataURL(file) to convert the entire photo into a Base64 string before loading it into an image element. That extra copy can increase memory pressure with large mobile photos.

The new path rejects empty files, obvious non-images, SVG and files over 50 MiB before loading. It uses URL.createObjectURL(file) to create a browser-local Blob URL, waits for the image to decode, and checks the decoded pixel count before sending the image through the existing MediaPipe flow. Images over 50 million pixels are stopped before canvas processing.

The old Blob URL is released with URL.revokeObjectURL() when the user replaces a photo, resets the tool or hits an error. An image load gets a 20-second timeout. If HEIC cannot be decoded by the browser, the page suggests saving a JPG copy. The selected photo still stays in the browser instead of being uploaded to an analysis server.

Making errors useful without collecting the photo

The updated diagnostic path distinguishes preflight, Blob URL creation and decode failures. It also records limited format groups and file-size bands. Analytics does not receive the original image bytes, filename, Blob URL or native error message.

I fixed another edge case in which a failed canvas snapshot could leave the loading state visible. That error now follows the cleanup path and is reported as canvas_snapshot.

Two new parameters, upload_format and upload_size_band, are emitted by the app but are not yet queryable as GA4 custom dimensions. Registering them failed with an Analytics Admin OAuth permission error (HTTP 403). Existing error-stage and device dimensions remain the available reporting tools.

Testing the change and checking the release

The changes passed 20 upload and recovery scenarios in desktop Chrome emulating an Android viewport and user agent. They covered valid images, damaged or unsupported files, file and pixel limits, Blob URL errors, reselection and canvas failure. A separate check exercised the real MediaPipe face-detection and result-rendering path.

The GitHub Pages deployment succeeded. On November 14, the JavaScript served by the live Richchecker KR page was byte-identical to js/script.js in the repository’s main branch.

There is no verified result yet for the affected physical Android devices, or a before-and-after completion-rate comparison. Removing the old file_read path makes that event disappear by design; it does not prove that every upload now succeeds. The next meaningful measurement is a device-by-device comparison of the new error stages and completed analyses over comparable periods.

Sources: Richchecker KR repository · Separating app and blog analytics on a shared host