Yalantis/uCrop · error · CImgArgumentException

[cimg_appname_math_parser] CImg<%s>::%s: %s: Specified kerne

Error message

[cimg_appname_math_parser] CImg<%s>::%s: %s: Specified kernel size (%ux%ux%ux%u = %u) does not match size of kernel variable (%u), in expression '%s'.

What it means

The kernel-side counterpart of the input size check in the same convolution opcode: the kernel variable (opcode[7]) element count must equal wK*hK*dK*sK. Immediately after validating the input size, the parser validates the kernel geometry; a mismatch aborts the expression before any convolution runs.

Source

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

                xstride = (int)mem[opcode[18]],
                ystride = (int)mem[opcode[19]],
                zstride = (int)mem[opcode[20]],
                xsize = opcode[27]==~0U?wI/xstride:(unsigned int)mem[opcode[27]],
                ysize = opcode[28]==~0U?hI/ystride:(unsigned int)mem[opcode[28]],
                zsize = opcode[29]==~0U?dI/zstride:(unsigned int)mem[opcode[29]];

              if (wI*hI*dI*sI!=size(opcode[2])) {
                _cimg_mp_strerr;
                throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                            "CImg<%s>::%s: %s: Specified input size (%ux%ux%ux%u = %u) does "
                                            "not match size of input variable (%u), in expression '%s'.",
                                            pixel_type(),_cimg_mp_calling_function,s_op,
                                            wI,hI,dI,sI,wI*hI*dI*sI,size(opcode[2]),
                                            s0);
              }
              if (wK*hK*dK*sK!=size(opcode[7])) {
                _cimg_mp_strerr;
                throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                            "CImg<%s>::%s: %s: Specified kernel size (%ux%ux%ux%u = %u) does "
                                            "not match size of kernel variable (%u), in expression '%s'.",
                                            pixel_type(),_cimg_mp_calling_function,s_op,
                                            wK,hK,dK,sK,wK*hK*dK*sK,size(opcode[7]),
                                            s0);
              }

              arg2 = !channel_mode?sI*sK:channel_mode==1?std::max(sI,sK):
                channel_mode==2?std::max(sI,sK)/std::min(sI,sK):1U;

              opcode[1] = pos = vector(xsize*ysize*zsize*arg2);
              opcode[3] = (ulongT)wI;
              opcode[4] = (ulongT)hI;
              opcode[5] = (ulongT)dI;
              opcode[6] = (ulongT)sI;
              opcode[8] = (ulongT)wK;
              opcode[9] = (ulongT)hK;
              opcode[10] = (ulongT)dK;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Ensure the kernel vector has exactly wK*hK*dK*sK elements (3x3 -> 9 values, 5x5 -> 25).
  2. Update the declared kernel geometry after any kernel-size change.
  3. Build the kernel with a geometry-matched constructor/fill in the same expression.
  4. Print/verify kernel length before the convolution call.

Example fix

// before
k = [1,2,3,4,5,6,7,8]; convolve(in, k, ..., 3,3,1,1, ...) // 8 != 9
// after
k = [1,2,3,4,5,6,7,8,9]; convolve(in, k, ..., 3,3,1,1, ...)
Defensive patterns

Strategy: validation

Validate before calling

size_t kLen = kernel.size();
unsigned long expect = (unsigned long)wK*hK*dK*sK;
if (kLen != expect) throw std::runtime_error("kernel geometry " + std::to_string(expect) + " != kernel size " + std::to_string(kLen));

Type guard

bool kernel_fits(const CImg<float>& k, unsigned wK, unsigned hK, unsigned dK, unsigned sK) {
  return (unsigned long)k.size() == (unsigned long)wK*hK*dK*sK;
}

Try / catch

try {
  img.fill(expr.c_str());
} catch (const CImgArgumentException& e) {
  // rebuild kernel with matching geometry
}

Prevention

When it happens

Trigger: Passing a kernel vector whose length does not match its declared 4D kernel geometry in the expression-level convolution call (e.g. a 3x3 kernel declared as 3x3x1x1=9 values but supplied with 8), or reusing a kernel variable resized elsewhere in the expression.

Common situations: Changing kernel size (3x3 to 5x5) without updating the declared geometry; building the kernel dynamically with fill() and getting a different length; mixing separable vs full kernels with wrong parameter counts.

Understand the failure class

Background: Tensor shape mismatch errors ("must have shape", "expected shape ... got ..."): when tensor dimensions disagree with what an op or layer was told to expect — this error's family across 6 libraries.

Related errors


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