Yalantis/uCrop · warning

invert(): LAPACK function dgetri_() returned error code

Error message

invert(): LAPACK function dgetri_() returned error code %d.

What it means

After a successful LU factorization, CImg::invert() calls LAPACK dgetri_() to compute the inverse; nonzero INFO means the inversion step failed (dgetri_ reports an invalid argument or an internal pivot problem). CImg then fills the matrix with zeros rather than throwing.

Solutions

  1. Verify the matrix is square and reasonably sized before calling invert()
  2. Use a consistent, complete LAPACK build in the NDK project (check that dgetrf_/dgetri_ come from the same library)
  3. Check the zero-filled result and fall back to an alternative inversion (e.g. solve-based or eigen-based)
  4. Reduce matrix dimensions or use block-wise inversion for huge matrices

Example fix

// before
CImg<float> inv = A.invert(true);
// after
if (A.width() != A.height() || A.width() == 0) throw std::runtime_error("invert needs a non-empty square matrix");
CImg<float> inv = A.invert(true);
Defensive patterns

Strategy: validation

Validate before calling

bool okForInvert(const CImg<float>& A) {
  return A.width() == A.height() && A.width() > 0 && A.width() < 100000;
}

Prevention

When it happens

Trigger: Calling invert(use_LU=true) when dgetri_ receives bad parameters — typically caused by an inconsistent matrix size, a corrupted IPIV pivot array, or insufficient WORK space on unusual builds.

Common situations: Very large matrices exceeding LAPACK integer ranges; custom/incomplete LAPACK builds in the JNI/NDK environment with mismatched dgetri_ signatures.

Related errors


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

Appendix: source

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

        _data[6] = (T)((b*f - e*c)/dete), _data[7] = (T)((d*c - a*f)/dete), _data[8] = (T)((a*e - d*b)/dete);
      } else {

#ifdef cimg_use_lapack
        int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N];
        Tfloat
          *const lapA = new Tfloat[N*N],
          *const WORK = new Tfloat[LWORK];
        cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l));
        cimg::getrf(N,lapA,IPIV,INFO);
        if (INFO)
          cimg::warn(_cimg_instance
                     "invert(): LAPACK function dgetrf_() returned error code %d.",
                     cimg_instance,
                     INFO);
        else {
          cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO);
          if (INFO)
            cimg::warn(_cimg_instance
                       "invert(): LAPACK function dgetri_() returned error code %d.",
                       cimg_instance,
                       INFO);
        }
        if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0);
        delete[] IPIV; delete[] lapA; delete[] WORK;
#else
        if (use_LU) { // LU solver
          CImg<Tfloat> A(*this,false), indx;
          bool d;
          A._LU(indx,d);
          cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width*_height,16*16))
          cimg_forX(*this,j) {
            CImg<Tfloat> col(1,_width,1,1,0);
            col(j) = 1;
            col._solve(A,indx);
            cimg_forX(*this,i) (*this)(j,i) = (T)col(i);
          }

View on GitHub (pinned to f788b534b4)