Yalantis/uCrop · error · CImgArgumentException

[" cimg_appname "_math_parser] CImg<%s>::%s: Unbalanced pare

Error message

[" cimg_appname "_math_parser] CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.

What it means

After tokenizing the math expression, the CImg parser tracks nesting depth (_level). If the level is non-zero at the end of parsing, some '(' or '[' was never closed (or a ')' / ']' was closed out of order), so it throws CImgArgumentException for unbalanced parentheses/brackets. This is a structural validation pass that always runs before the compiled expression is returned.

Source

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

          }
          *(pd++) = (unsigned int)(mode>=1 || is_escaped?_level + (mode==1):
                                   *ps=='(' || *ps=='['?_level++:
                                   *ps==')' || *ps==']'?--_level:
                                   _level);
          mode = next_mode;
          is_escaped = next_is_escaped;
          next_is_escaped = false;
        }
        if (mode) {
          cimg::strellipsize(_expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unterminated string literal, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      _expr._data);
        }
        if (_level) {
          cimg::strellipsize(_expr,64);
          throw CImgArgumentException("[" cimg_appname "_math_parser] "
                                      "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.",
                                      pixel_type(),_cimg_mp_calling_function,
                                      _expr._data);
        }
        return res;
      }

      // Find and return index of current image 'imgin' within image list 'imglist'.
      unsigned int get_mem_img_index() {
        if (mem_img_index==~0U) {
          if (&imgout>=imglist.data() && &imgout<imglist.end())
            mem_img_index = const_scalar((double)(&imgout - imglist.data()));
          else {
            unsigned int pos = ~0U;
            cimglist_for(imglist,l)
              if (imgout._data==imglist[l]._data && imgout.is_sameXYZC(imglist[l])) { pos = l; break; }
            if (pos!=~0U) mem_img_index = const_scalar((double)pos);
          }

View on GitHub (pinned to f788b534b4)

Solutions

  1. Count and match every '(' with ')' and every '[' with ']' in the expression string
  2. Log the full expression (the error truncates it to 64 chars) and check the tail for dangling open brackets
  3. If generating expressions in code, build them with a small helper that tracks nesting depth and asserts balance before calling CImg
  4. Validate the expression with a paren-balance check before passing it to the CImg API

Example fix

// before
img.fill("sin(x*(cos(y)"); // unbalanced: missing one ')'
// after
img.fill("sin(x*(cos(y)))");
Defensive patterns

Strategy: validation

Validate before calling

// C++: verify parentheses/bracket balance before calling CImg
bool brackets_balanced(const std::string& e) {
  int d = 0;
  for (char c : e) {
    if (c == '(' || c == '[') ++d;
    else if (c == ')' || c == ']') --d;
    if (d < 0) return false;
  }
  return d == 0;
}
if (!brackets_balanced(expr)) throw std::invalid_argument("unbalanced parentheses in expression");

Type guard

bool has_balanced_brackets(const std::string& e); // see validationCode

Try / catch

try {
  img.fill(expr);
} catch (const cimg_library::CImgArgumentException& e) {
  std::cerr << "Unbalanced brackets in: " << expr << std::endl;
}

Prevention

When it happens

Trigger: Calling a CImg function with an expression string such as img.fill("sin(x*(cos(y)") where an opening '(' or '[' lacks its closing partner, or brackets are closed in the wrong order like "(x]")". Also occurs when a builder or template generates expressions with conditionally dropped closing brackets.

Common situations: Hand-written formulas with deeply nested function calls; code-generated expressions where a branch omits a closing paren; editing expressions by hand and deleting one side of a bracket pair; macro/template substitution producing broken formulas.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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