Yalantis/uCrop · error · CImgArgumentException
remove(): Invalid remove request at positions %u->%u.
Error message
remove(): Invalid remove request at positions %u->%u.
What it means
CImgList::remove(pos1,pos2) throws when the normalized start position npos1 is greater than or equal to the list size _width, meaning the entire requested removal range lies past the end of the list. Nothing can be removed, so the library raises CImgArgumentException with the normalized position range.
Source
Thrown at ucrop/src/main/jni/CImg.h:65952
//! Insert n copies of the list \c list at position \c pos of the current list \newinstance.
template<typename t>
CImgList<T> get_insert(const unsigned int n, const CImgList<t>& list, const unsigned int pos=~0U,
const bool is_shared=false) const {
return (+*this).insert(n,list,pos,is_shared);
}
//! Remove all images between from indexes.
/**
\param pos1 Starting index of the removal.
\param pos2 Ending index of the removal.
**/
CImgList<T>& remove(const unsigned int pos1, const unsigned int pos2) {
const unsigned int
npos1 = pos1<pos2?pos1:pos2,
tpos2 = pos1<pos2?pos2:pos1,
npos2 = tpos2<_width?tpos2:_width - 1;
if (npos1>=_width)
throw CImgArgumentException(_cimglist_instance
"remove(): Invalid remove request at positions %u->%u.",
cimglist_instance,
npos1,tpos2);
else {
if (tpos2>=_width)
throw CImgArgumentException(_cimglist_instance
"remove(): Invalid remove request at positions %u->%u.",
cimglist_instance,
npos1,tpos2);
for (unsigned int k = npos1; k<=npos2; ++k) _data[k].assign();
const unsigned int nb = 1 + npos2 - npos1;
if (!(_width-=nb)) return assign();
if (_width>(_allocated_width>>4) || _allocated_width<=16) { // Removing items without reallocation
if (npos1!=_width)
std::memmove((void*)(_data + npos1),(void*)(_data + npos2 + 1),sizeof(CImg<T>)*(_width - npos1));
std::memset((void*)(_data + _width),0,sizeof(CImg<T>)*nb);
} else { // Removing items with reallocationView on GitHub (pinned to f788b534b4)
Solutions
- Check list.size() and skip the call when pos1 >= size() before removing
- Clamp positions: pos1 = min(pos1, size-1), pos2 = min(pos2, size-1)
- Verify the range wasn't already removed (guard against double removal)
Example fix
// before list.remove(4, 6); // throws when list.size() <= 4 // after if (list.size() > 4) list.remove(4, std::min(6u, list.size() - 1));
Defensive patterns
Strategy: validation
Validate before calling
if (list.is_empty() || std::min(pos1,pos2) >= list.size()) return; // skip out-of-range removal
Try / catch
try { list.remove(pos1, pos2); } catch (const CImgArgumentException& e) { /* log and skip */ } Prevention
- Check size() before batch removal
- Avoid double removal of the same range
- Use size()-1 as the maximum valid index
When it happens
Trigger: list.remove(pos1,pos2) where min(pos1,pos2) >= list.size(), e.g. removing indices 4->6 from a 4-element list, or calling remove on an empty list.
Common situations: Reusing cached index ranges after the list shrank; removing a batch twice (second call is out of range); calling on an empty list built from a failed load.
Related errors
- images(): Specified sub-list indices (%u->%u) are out of bou
- load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u)
- cimg::fopen(): Specified file path is (null).
- cimg::fopen(): File '%s', specified mode is (null).
- 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/b27f4cd1bca85d12.
Report an issue: GitHub.