Yalantis/uCrop · warning

load_off(): Failed to read primitive %u/%u from file

Error message

load_off(): Failed to read primitive %u/%u from file '%s'.

What it means

CImg::load_off() reads Wavefront OFF mesh files; each primitive line starts with a type code (1 = vertex, etc.). When the fscanf for a primitive or its payload fails, CImg warns with the primitive index (nb_read of nb_primitives), skips the malformed line, and continues reading, so the resulting mesh may be missing elements.

Solutions

  1. Open the file at the reported primitive index and fix or remove the malformed line
  2. Re-export the mesh from a known-good tool with standard OFF formatting
  3. Check the file is complete (compare face/vertex counts in the header to actual lines)
  4. Validate the OFF file with an external checker before loading
  5. Treat missing primitives in the loaded mesh as a signal to abort rather than use the partial geometry

Example fix

// before
CImg<float> points; CImgList<unsigned int> faces;
primitives.load_off(points, faces, "mesh.off"); // silently partial on malformed lines
// after
std::ifstream in("mesh.off");
std::string tok; in >> tok >> nv >> nf >> ne;
// count non-empty lines after header; compare with nf before loading
if (countPrimitiveLines(in) != nf) throw std::runtime_error("mesh.off is truncated");
Defensive patterns

Strategy: validation

Validate before calling

bool offFilePlausible(const char* path) {
  std::ifstream in(path);
  std::string h; unsigned nv, nf, ne;
  if (!(in >> h >> nv >> nf >> ne) || h != "OFF") return false;
  unsigned lines = 0; std::string s;
  while (std::getline(in, s)) if (!s.empty()) ++lines;
  return lines >= nv + nf;
}

Prevention

When it happens

Trigger: Loading an OFF file whose primitive section has a truncated or malformed line — e.g. a vertex line without 3 coordinates or missing text after the type code — or a prematurely terminated file.

Common situations: OFF files exported by buggy/non-conforming tools; manual edits that break a line; file truncated during download; Windows/Mac line-ending or extra-token oddities the parser's format string rejects.

Related errors


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

Appendix: source

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

        }
        (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z;
      }

      // Read primitive data.
      primitives.assign();
      colors.assign();
      bool stop_flag = false;
      while (!stop_flag) {
        float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f;
        unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0;
        *line = 0;
        if ((err = std::fscanf(nfile,"%u",&prim))!=1) stop_flag = true;
        else {
          ++nb_read;
          switch (prim) {
          case 1 : {
            if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line._data))<2) {
              cimg::warn(_cimg_instance
                         "load_off(): Failed to read primitive %u/%u from file '%s'.",
                         cimg_instance,
                         nb_read,nb_primitives,filename?filename:"(FILE*)");

              err = std::fscanf(nfile,"%*[^\n] ");
            } else {
              err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2);
              CImg<tf>::vector(i0).move_to(primitives);
              CImg<tc>::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors);
            }
          } break;
          case 2 : {
            if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line._data))<2) {
              cimg::warn(_cimg_instance
                         "load_off(): Failed to read primitive %u/%u from file '%s'.",
                         cimg_instance,
                         nb_read,nb_primitives,filename?filename:"(FILE*)");

View on GitHub (pinned to f788b534b4)