Yalantis/uCrop · error · CImgIOException

save_tiff(): Failed to open stream for file '%s'.

Error message

save_tiff(): Failed to open stream for file '%s'.

What it means

save_tiff calls TIFFOpen (libtiff) on the given filename; if libtiff cannot open the file for writing (bad path, missing directory, permissions, read-only filesystem), the returned TIFF* is null and CImgIOException 'Failed to open stream' is thrown. This is an OS-level open failure surfaced through libtiff.

Source

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

#else
      ulongT siz = 0;
      cimglist_for(*this,l) siz+=_data[l].size();
      const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images
      TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4");
      if (tif) {
        double val_min = cimg::type<double>::inf(), val_max = -val_min;
        cimglist_for(*this,l) {
          double l_val_min, l_val_max = (double)_data[l].max_min(l_val_min);
          if (l_val_min<val_min) val_min = l_val_min;
          if (l_val_max>val_max) val_max = l_val_max;
        }
        for (unsigned int dir = 0, l = 0; l<_width; ++l) {
          const CImg<T>& img = (*this)[l];
          cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description,val_min,val_max);
        }
        TIFFClose(tif);
      } else
        throw CImgIOException(_cimglist_instance
                              "save_tiff(): Failed to open stream for file '%s'.",
                              cimglist_instance,
                              filename);
#endif
      return *this;
    }

    //! Save list as a gzipped file, using external tool 'gzip'.
    /**
      \param filename Filename to write data to.
    **/
    const CImgList<T>& save_gzip_external(const char *const filename) const {
      if (!filename)
        throw CImgIOException(_cimglist_instance
                              "save_gzip_external(): Specified filename is (null).",
                              cimglist_instance);
      CImg<charT> command(1024), filename_tmp(256), body(256);
      const char

View on GitHub (pinned to f788b534b4)

Solutions

  1. Ensure the target directory exists and is writable (create it, e.g. cimg::mkdir or std::filesystem::create_directories).
  2. Check file permissions / storage permissions of the process before saving.
  3. Try saving to an app-writable location (e.g. cache dir) and move the file afterwards.

Example fix

// before
list.save_tiff("/sdcard/out.tif"); // no storage permission
// after
std::filesystem::create_directories("/sdcard/DCIM/myapp");
if (std::filesystem::is_directory("/sdcard/DCIM/myapp"))
  list.save_tiff("/sdcard/DCIM/myapp/out.tif");
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure directory exists and is writable before saving
std::filesystem::path p(filename);
if (p.has_parent_path()) std::filesystem::create_directories(p.parent_path());
FILE *t = std::fopen(filename, "ab"); bool writable = t != nullptr; if (t) std::fclose(t);

Try / catch

try { list.save_tiff(filename); } catch (CImgIOException &e) { std::fprintf(stderr, "cannot open %s: %s", filename, e.what()); /* fallback path */ }

Prevention

When it happens

Trigger: save_tiff with a path in a non-existent directory, no write permission, an unwritable device, or a filename too long/invalid for the OS; also when TIFF support was compiled in but the path is a directory.

Common situations: Read-only USB/app storage (especially Android JNI, as here under ucrop/jni); wrong output directory; sandboxed process lacking storage permission.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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