Yalantis/uCrop · error · CImgArgumentException

cimg::dialog(): No buttons have been defined.

Error message

cimg::dialog(): No buttons have been defined.

What it means

cimg::dialog() builds its message box by rendering each non-null button label into button images; the box needs at least one button to draw. If every button*_label argument is NULL, the buttons list stays empty (buttons._width == 0) and CImg throws CImgArgumentException because a dialog with no clickable buttons cannot be constructed.

Solutions

  1. Always pass at least one non-null button label, e.g. cimg::dialog("Title","Msg","OK") instead of passing NULL for button1_label.
  2. Validate the label arguments (or the array feeding them) before calling dialog(), and fall back to a default "OK" label when none are provided.
  3. Check the argument order — the first non-null label lands in button1; make sure the intended label is not shifted into a wrong or unused slot.
  4. If button labels are dynamic, guard the call: only invoke cimg::dialog() when the labels vector is non-empty, otherwise use a plain log message.

Example fix

// before
cimg::dialog("Load error", "Cannot open file", NULL, NULL, NULL, NULL, NULL, NULL); // no buttons -> throws
// after
if (buttonLabels.empty()) buttonLabels.push_back("OK");
cimg::dialog("Load error", "Cannot open file", buttonLabels[0],
             buttonLabels.size()>1?buttonLabels[1].c_str():NULL,
             buttonLabels.size()>2?buttonLabels[2].c_str():NULL,
             NULL, NULL, NULL);
Defensive patterns

Strategy: validation

Validate before calling

// Require at least one non-null button label before opening a dialog
bool hasButton(const char* b1, const char* b2, const char* b3,
               const char* b4, const char* b5, const char* b6) {
  return b1 || b2 || b3 || b4 || b5 || b6;
}
if (hasButton(b1,b2,b3,b4,b5,b6)) {
  cimg::dialog(title, msg, b1?b1:"", b2, b3, b4, b5, b6);
} else {
  cimg::dialog(title, msg, "OK", NULL, NULL, NULL, NULL, NULL); // default button
}

Try / catch

try {
  cimg::dialog(title, msg, b1, b2, b3, b4, b5, b6);
} catch (CImgArgumentException& e) {
  std::cerr << "Dialog error: " << e.what() << "\n";
  cimg::dialog(title, msg, "OK", NULL, NULL, NULL, NULL, NULL); // retry with default
}

Prevention

When it happens

Trigger: Calling cimg::dialog(title,msg,...) with all six button label arguments set to NULL (or passing only NULLs on a path where default labels were expected), causing the `if (!buttons._width)` check to fail.

Common situations: Programmatically building button labels and passing NULL when the label list ends up empty; forwarding user-supplied/optional button names that were never initialized; porting code from another dialog API where a null-button dialog is legal; typos where the single intended "OK" label is passed in the wrong position or left NULL.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

        black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 };

      // Create buttons and canvas graphics.
      CImgList<unsigned char> buttons, cbuttons, sbuttons;
      if (button1_label) {
        CImg<unsigned char>().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons);
        if (button2_label) {
          CImg<unsigned char>().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons);
          if (button3_label) {
            CImg<unsigned char>().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons);
            if (button4_label) {
              CImg<unsigned char>().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons);
              if (button5_label) {
                CImg<unsigned char>().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons);
                if (button6_label) {
                  CImg<unsigned char>().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons);
                }}}}}}
      if (!buttons._width)
        throw CImgArgumentException("cimg::dialog(): No buttons have been defined.");
      cimglist_for(buttons,l) buttons[l].resize(-100,-100,1,3);

      unsigned int bw = 0, bh = 0;
      cimglist_for(buttons,l) { bw = std::max(bw,buttons[l]._width); bh = std::max(bh,buttons[l]._height); }
      bw+=8; bh+=8;
      if (bw<64) bw = 64;
      if (bw>128) bw = 128;
      if (bh<24) bh = 24;
      if (bh>48) bh = 48;

      CImg<unsigned char> button(bw,bh,1,3);
      button.draw_rectangle(0,0,bw - 1,bh - 1,gray);
      button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white);
      button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black);
      button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2);
      CImg<unsigned char> sbutton(bw,bh,1,3);
      sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray);
      sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black);

View on GitHub (pinned to f788b534b4)