Yalantis/uCrop · error · CImgArgumentException

save_exr(): Specified filename is (null).

Error message

save_exr(): Specified filename is (null).

What it means

save_exr() validates its filename argument before touching OpenEXR and throws CImgArgumentException on a null C-string, printing the literal '(null)'. It is the standard null-check guard used by all CImg savers, raised before the volumetric-slice warning or any file I/O.

Source

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

                          voxel_size[0],voxel_size[1],voxel_size[2]);
      err+=cimg_snprintf(header._data + err,128,"TYPE=%s\nCPU=%s\n",
                         inrtype,cimg::endianness()?"sun":"decm");
      std::memset(header._data + err,'\n',252 - err);
      std::memcpy(header._data + 252,"##}\n",4);
      cimg::fwrite(header._data,256,nfile);
      cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile);
      if (!file) cimg::fclose(nfile);
      return *this;
    }

    //! Save image as an OpenEXR file.
    /**
       \param filename Filename, as a C-string.
       \note The OpenEXR file format is <a href="http://en.wikipedia.org/wiki/OpenEXR">described here</a>.
    **/
    const CImg<T>& save_exr(const char *const filename) const {
      if (!filename)
        throw CImgArgumentException(_cimg_instance
                                    "save_exr(): Specified filename is (null).",
                                    cimg_instance);
      if (is_empty()) { cimg::fempty(0,filename); return *this; }
      if (_depth>1)
        cimg::warn(_cimg_instance
                   "save_exr(): Instance is volumetric, only the first slice will be saved in file '%s'.",
                   cimg_instance,
                   filename);

#ifndef cimg_use_openexr
      return save_other(filename);
#else
      Imf::Rgba *const ptrd0 = new Imf::Rgba[(size_t)_width*_height], *ptrd = ptrd0, rgba;
      switch (_spectrum) {
      case 1 : { // Grayscale image
        for (const T *ptr_r = data(), *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_r<ptr_e;) {
          rgba.r = (half)(*(ptr_r));
          rgba.g = (half)(*(ptr_r));

View on GitHub (pinned to f788b534b4)

Solutions

  1. Check the filename for null/empty before the call and raise a clear error identifying the missing path source.
  2. Fix the upstream path producer (env var, config key, argument parsing) so it yields a valid string.
  3. If holding an open stream is more natural, use a writer overload accepting FILE* if available for your format, or open the file yourself first.
  4. Centralize filename validation in a save helper so all export paths get the same guard.

Example fix

// before
const char *out = getenv("EXR_PATH");
img.save_exr(out); // throws when EXR_PATH unset

// after
const char *out = getenv("EXR_PATH");
if (!out || !*out) throw std::runtime_error("EXR_PATH is required");
img.save_exr(out);
Defensive patterns

Strategy: validation

Validate before calling

if (!filename || !*filename)
  throw std::invalid_argument("save_exr: filename is null or empty");

Type guard

bool valid_path(const char* p) { return p != nullptr && *p != '\0'; }

Try / catch

try {
  img.save_exr(path.c_str());
} catch (const CImgArgumentException& e) {
  std::fprintf(stderr, "EXR save failed, no filename: %s\n", e.what());
}

Prevention

When it happens

Trigger: Calling CImg::save_exr(NULL) or forwarding a null filename through save(); typically from an uninitialized pointer, a getenv() that returned NULL, or a failed path computation whose result was not checked. Note this error requires OpenEXR support to even be reachable in some builds.

Common situations: EXR output path read from config/env that was unset; string helper returning NULL on failure; caller passing a std::string::c_str() of an empty-constructed-from-null pointer.

Related errors


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