Yalantis/uCrop · error · CImgIOException

load_jxl(): Failed to set decode buffer

Error message

load_jxl(): Failed to set decode buffer '%s'.

What it means

After allocating imgData, load_jxl() hands the buffer to libjxl with JxlDecoderSetImageOutBuffer. A non-success return means libjxl refused the output buffer, so the decoder is destroyed and this error is thrown. Typically a size/format mismatch between the allocated buffer and what the decoder requires.

Solutions

  1. Rebuild JNI code against the deployed libjxl version so JxlPixelFormat and size semantics match.
  2. Confirm imgData.assign(imgDataSize) succeeded (buffer.data() non-null, correct size).
  3. Upgrade CImg; check known libjxl issues around SetImageOutBuffer for your version.

Example fix

// before
imgData.assign(imgDataSize); // OOM -> null/short buffer
JxlDecoderSetImageOutBuffer(...); // fails
// after
imgData.assign(imgDataSize);
if (imgData.size() != imgDataSize) { /* handle alloc failure */ }
JxlDecoderSetImageOutBuffer(dec, &format, imgData.data(), imgDataSize);
Defensive patterns

Strategy: try-catch

Try / catch

try { img.load_jxl(path); } catch (CImgIOException& e) { if (strstr(e.what(), "decode buffer")) reportAllocationOrAbiIssue(e); }

Prevention

When it happens

Trigger: JxlDecoderSetImageOutBuffer(decoder, &format, imgData.data(), imgDataSize) returns != JXL_DEC_SUCCESS during load_jxl()'s NEED_IMAGE_OUT_BUFFER handling.

Common situations: imgDataSize from JxlDecoderImageOutBufferSize not matching the assigned buffer (allocation failure of imgData.assign), or format struct mutated between the two calls (ABI mismatch across libjxl versions).

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08). Data as JSON: /api/errors/94753a7202cb6961. Report an issue: GitHub.

Appendix: source

Thrown at ucrop/src/main/jni/CImg.h:57215

          }
          hasAlpha = jxlInfo.alpha_bits!=0;
          nChannels = hasAlpha?jxlInfo.num_color_channels + 1:jxlInfo.num_color_channels;
          isGray = jxlInfo.num_color_channels==1;
        } else if (status==JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
          std::size_t imgDataSize = 0;
          format.num_channels = nChannels;
          format.data_type = jxlInfo.bits_per_sample==16?JXL_TYPE_UINT16:JXL_TYPE_UINT8;
          if (JXL_DEC_SUCCESS!=JxlDecoderImageOutBufferSize(decoder,&format,&imgDataSize)) {
            JxlDecoderDestroy(decoder);
            throw CImgIOException(_cimg_instance
                                  "load_jxl(): Failed to decode image data '%s'.",
                                  cimg_instance,
                                  nfilename);
          }
          imgData.assign(imgDataSize);
          if (JXL_DEC_SUCCESS!=JxlDecoderSetImageOutBuffer(decoder,&format,(void*)imgData.data(),imgDataSize)) {
            JxlDecoderDestroy(decoder);
            throw CImgIOException(_cimg_instance
                                  "load_jxl(): Failed to set decode buffer '%s'.",
                                  cimg_instance,
                                  nfilename);
          }
        }
      }

      assign(jxlInfo.xsize,jxlInfo.ysize,1,nChannels);
      T
        *ptr_r = data(0,0,0,0),
        *ptr_g = isGray?0:data(0,0,0,1),
        *ptr_b = isGray?0:data(0,0,0,2),
        *ptr_a = !hasAlpha?0:data(0,0,0,isGray?1:3);
      switch (jxlInfo.bits_per_sample) {
      case 8: {
        cimg_forY(*this,y) {
          const uint8_t *ptrs = (uint8_t*)&imgData[y*_width*_spectrum*sizeof(uint8_t)];
          cimg_forX(*this,x) {

View on GitHub (pinned to f788b534b4)