Yalantis/uCrop · error · CImgArgumentException

[cimg_appname_math_parser] CImg<%s>::%s: %s: Invalid type '%

Error message

[cimg_appname_math_parser] CImg<%s>::%s: %s: Invalid type '%s' for variable '%s' (expected 'scalar'), in expression '%s'.

What it means

For 3-argument loops, the named loop variable must be an existing, non-constant scalar variable slot. After resolving the variable position, CImg checks is_scalar(slot) && !is_const_scalar(slot); if the variable is a vector type or was declared constant, it throws this error reporting the actual type via s_type(arg2).

Source

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

              if (s1<se1) { // Version with 3 arguments
                variable_name.assign(s0,(unsigned int)(s1 + 1 - s0)).back() = 0;
                cimg::strpare(variable_name,false,true);
                if (!cimg::is_varname(variable_name)) { // Invalid variable name
                  cimg::strellipsize(variable_name,64);
                  _cimg_mp_strerr;
                  throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                              "CImg<%s>::%s: %s: Invalid loop variable name '%s', "
                                              "in expression '%s'.",
                                              pixel_type(),_cimg_mp_calling_function,s_op,
                                              variable_name._data,s0);
                }
                get_variable_pos(variable_name,arg2,arg3);
                arg2 = arg3!=~0U?reserved_label[arg3]:arg2!=~0U?variable_pos[arg2]:~0U; // Variable slot
                if (arg2!=~0U && (!is_scalar(arg2) ||
                                  is_const_scalar(arg2))) { // Variable is not a vector or is a constant->error
                  cimg::strellipsize(variable_name,64);
                  _cimg_mp_strerr;
                  throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                              "CImg<%s>::%s: %s: Invalid type '%s' for variable '%s' "
                                              "(expected 'scalar'), in expression '%s'.",
                                              pixel_type(),_cimg_mp_calling_function,s_op,
                                              s_type(arg2)._data,variable_name._data,s0);
                } else if (arg2==~0U) { // Variable does not exist -> create it
                  arg2 = scalar();
                  if (arg3!=~0U) reserved_label[arg3] = arg2;
                  else {
                    if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0);
                    variable_pos[variable_def._width] = arg2;
                    variable_name.move_to(variable_def);
                  }
                  memtype[arg2] = -1;
                }
                arg3 = compile(++s1,se1,depth1,0,block_flags);
                _cimg_mp_check_type(arg3,3,1,0);
              } else { // Version with 2 arguments
                arg2 = ~0U;

View on GitHub (pinned to f788b534b4)

Solutions

  1. Use a plain scalar variable as the loop variable (declare with `x = 0` before the loop, not vector())
  2. Rename the loop variable so it doesn't shadow a vector or reserved constant (pi, e, w, h, d, s...)
  3. Initialize the variable with a non-constant expression so it gets a mutable scalar slot
  4. Use the 2-argument loop form with an implicit counter variable

Example fix

// before
img.fill("v = vector(3); for(v, 0, 5, ...)" ); // v is a vector
// after
img.fill("i = 0; for(i, 0, 5, ...)");
Defensive patterns

Strategy: validation

Validate before calling

// Before a 3-arg loop, ensure the counter variable is declared as a plain mutable scalar:
// "i = 0; for(i, 0, n, ...)" — never reuse a vector() variable as the counter.
boolean loopVarIsScalarDecl(String expr, String var) {
  return expr.matches("(?s).*\\b" + var + "\\s*=\\s*[-+0-9.].*\\bfor\\s*\\(\\s*" + var + "\\b.*");
}

Try / catch

try { img.fill(expr); } catch (CImgArgumentException e) { if (e.getMessage().contains("Invalid type") && e.getMessage().contains("expected 'scalar'")) { throw new IllegalArgumentException("Loop variable must be a mutable scalar, not a vector or constant"); } throw e; }

Prevention

When it happens

Trigger: Using a vector variable as a loop variable (`for(v..., ...)` where v=vector(...)), or a variable captured as a constant (e.g. a constant literal binding or a const-folded slot), in `for`/`while`/`repeat` expressions compiled by fill()/evaluate().

Common situations: Reusing an existing vector name for the loop counter; declaring the variable with a constant expression that the parser marked const; shadowing a built-in constant name (pi, e, w, h, d, s) as loop variable.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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