Yalantis/uCrop · error · CImgArgumentException

[cimg_appname_math_parser] CImg<%s>::%s: %s: Invalid %slvalu

Error message

[cimg_appname_math_parser] CImg<%s>::%s: %s: Invalid %slvalue '%s', in expression '%s'.

What it means

The left-hand side of an assignment in a math-parser expression must be a valid assignable target (a variable or vector element). If no assignment form matches, the parser reports the target as an invalid lvalue; if the target is a const scalar it is flagged as such.

Source

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

                  CImg<ulongT>::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)size(arg1)).
                    move_to(code);
                else // From scalar
                  CImg<ulongT>::vector((ulongT)mp_vector_init,arg1,1,(ulongT)size(arg1),arg2).
                    move_to(code);
                _cimg_mp_return(arg1);
              }

              if (is_reserved(arg1)) { // Scalar variable: s = scalar
                _cimg_mp_check_type(arg2,2,1,0);
                CImg<ulongT>::vector((ulongT)mp_copy,arg1,arg2).move_to(code);
                _cimg_mp_return(arg1);
              }
            }

            // No assignment expressions match -> error.
            cimg::strellipsize(variable_name,64);
            _cimg_mp_strerr;
            throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                        "CImg<%s>::%s: %s: Invalid %slvalue '%s', "
                                        "in expression '%s'.",
                                        pixel_type(),_cimg_mp_calling_function,s_op,
                                        arg1!=~0U && is_const_scalar(arg1)?"const ":"",
                                        variable_name._data,s0);
          }
        }

        // Apply unary/binary/ternary operators. The operator precedences should be the same as in C++.
        is_sth = true;
        for (s = ss; s<se1; ++s) // Do a first pass to quickly skip costly operator checks that require for() loop
          if (cimg::_cimg_math_parser_check_operator[(unsigned char)*s] && level[s - expr._data]==clevel) {
            is_sth = false; break;
          }
        if (is_sth) goto cimg_skip_iterative_operator_parsing;

        for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1
          if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps &&

View on GitHub (pinned to f788b534b4)

Solutions

  1. Make the left side a plain variable name that is not const
  2. Swap operands if the assignment direction is reversed
  3. Store intermediate results in a mutable variable first

Example fix

// before
sin(x) = 3;
// after
y = sin(x);
Defensive patterns

Strategy: validation

Validate before calling

function isPlainLhs(expr) {
  const m = expr.match(/([^=])=([^=]|$)/);
  if (!m) return true;
  return /^[A-Za-z_]\w*\s*=/.test(expr.trim());
}

Try / catch

try {
  img.evaluate(expr);
} catch (e) {
  if (/Invalid .*lvalue/.test(String(e))) {
    // rewrite LHS as a mutable variable
  } else throw e;
}

Prevention

When it happens

Trigger: Writing assignments to literals, function calls, or const scalars, e.g. '5 = x', 'sin(x) = 3', or 'const_var = 1'.

Common situations: Reversed assignment directions after refactoring, typos where the intended '=' became '==' or vice versa, attempts to mutate const values.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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