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 charView on GitHub (pinned to f788b534b4)
Solutions
- Ensure the target directory exists and is writable (create it, e.g. cimg::mkdir or std::filesystem::create_directories).
- Check file permissions / storage permissions of the process before saving.
- 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
- Create the output directory before saving
- Request/check storage permissions on Android
- Use app-writable cache directories, then move files
- Catch CImgIOException around all file saves
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
- save_tiff(): Failed to open file '%s' for writing.
- cimg::fopen(): Specified file path is (null).
- cimg::fopen(): File '%s', specified mode is (null).
- cimg::fopen(): Failed to open file '%s' with mode '%s'.
- cimg::fread(): Invalid reading request of %u %s%s from file
AI-assisted analysis of Yalantis/uCrop@f788b534b4 (2026-09-08).
Data as JSON: /api/errors/ae6c1f6562309896.
Report an issue: GitHub.