DrKLO/Telegram · error

%s: can't read ICC profile from %s

Error message

%s: can't read ICC profile from %s

What it means

After allocating the ICC buffer, jpegtran reads the profile data with fread(icc_profile, icc_len, 1, icc_file) at jpegtran.c:521. If fread returns less than 1 (fewer than icc_len bytes read), the read failed. This can happen if the file shrank between the size determination and the read, or there is an I/O error.

Source

Thrown at TMessagesProj/jni/mozjpeg/jpegtran.c:522

  if (icc_filename != NULL) {
    if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) {
      fprintf(stderr, "%s: can't open %s\n", progname, icc_filename);
      exit(EXIT_FAILURE);
    }
    if (fseek(icc_file, 0, SEEK_END) < 0 ||
        (icc_len = ftell(icc_file)) < 1 ||
        fseek(icc_file, 0, SEEK_SET) < 0) {
      fprintf(stderr, "%s: can't determine size of %s\n", progname,
              icc_filename);
      exit(EXIT_FAILURE);
    }
    if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) {
      fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname);
      fclose(icc_file);
      exit(EXIT_FAILURE);
    }
    if (fread(icc_profile, icc_len, 1, icc_file) < 1) {
      fprintf(stderr, "%s: can't read ICC profile from %s\n", progname,
              icc_filename);
      free(icc_profile);
      fclose(icc_file);
      exit(EXIT_FAILURE);
    }
    fclose(icc_file);
    if (copyoption == JCOPYOPT_ALL)
      copyoption = JCOPYOPT_ALL_EXCEPT_ICC;
  }

#ifdef PROGRESS_REPORT
  start_progress_monitor((j_common_ptr)&dstinfo, &progress);
#endif

  /* Specify data source for decompression */
  if (jpeg_c_int_param_supported(&dstinfo, JINT_COMPRESS_PROFILE) &&
      jpeg_c_get_int_param(&dstinfo, JINT_COMPRESS_PROFILE)
        == JCP_MAX_COMPRESSION)

View on GitHub (pinned to 45ab8f4308)

Solutions

  1. Copy the ICC profile to a stable local temp file and use that path
  2. Ensure no other process writes to or truncates the ICC file while jpegtran runs
  3. Verify file integrity (checksum) before passing it

Example fix

// before
// icc_path shared, may be truncated by another process

// after
// copy to exclusive temp file
char tmp[256];
snprintf(tmp, sizeof(tmp), "%s/icc_%d.tmp", app_internal_dir, getpid());
copy_file(icc_path, tmp);
// pass tmp to jpegtran -icc, delete after
Defensive patterns

Strategy: validation

Validate before calling

// Copy ICC file to a private temp file to prevent concurrent modification
int stage_icc_file(const char *src, char *tmp, size_t tmp_len) {
    snprintf(tmp, tmp_len, "/tmp/icc_%d.icc", getpid());
    FILE *in = fopen(src, "rb");
    if (!in) return -1;
    FILE *out = fopen(tmp, "wb");
    if (!out) { fclose(in); return -1; }
    char buf[4096]; size_t n;
    while ((n = fread(buf, 1, sizeof(buf), in)) > 0)
        if (fwrite(buf, 1, n, out) != n) { fclose(in); fclose(out); return -1; }
    fclose(in); fclose(out);
    return 0;
}

Prevention

When it happens

Trigger: The ICC file was truncated or modified between the fseek/ftell and the fread call. A filesystem error during read. The file is on a failing storage device. A race condition where another process truncates the file concurrently.

Common situations: Temp ICC file on Android external storage that gets unmounted. File on network storage with a dropped connection. Concurrent process writes/truncates the ICC file while jpegtran reads it.

Related errors


AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14). Data as JSON: /api/errors/c3d1f9a3830bfd86. Report an issue: GitHub.