DrKLO/Telegram · error

%s: can't open %s for reading

Error message

%s: can't open %s for reading

What it means

jpegtran calls fopen(argv[file_index], READ_BINARY) to open the input JPEG at jpegtran.c:494. If fopen returns NULL, the file does not exist, is not readable by the current user, or the path is malformed. The program prints the error and immediately calls exit(EXIT_FAILURE).

Source

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

  } else {
    if (file_index != argc - 1) {
      fprintf(stderr, "%s: must name one input and one output file\n",
              progname);
      usage();
    }
  }
#else
  /* Unix style: expect zero or one file name */
  if (file_index < argc - 1) {
    fprintf(stderr, "%s: only one input file\n", progname);
    usage();
  }
#endif /* TWO_FILE_COMMANDLINE */

  /* Open the input file. */
  if (file_index < argc) {
    if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
      fprintf(stderr, "%s: can't open %s for reading\n", progname,
              argv[file_index]);
      exit(EXIT_FAILURE);
    }
  } else {
    /* default input file is stdin */
    fp = read_stdin();
  }

  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);

View on GitHub (pinned to 45ab8f4308)

Solutions

  1. Verify the file exists and is readable before invoking: `access(path, R_OK) == 0`
  2. Use an absolute path, not a relative one, especially when calling from JNI where cwd may differ
  3. Check file permissions: `ls -l <path>` and ensure the calling process has read access
  4. If on Android, copy the file to the app's internal storage (`getFilesDir()`) and pass that path to jpegtran

Example fix

// before (C caller)
int ret = system("jpegtran /data/media/photo.jpg -outfile out.jpg");

// after
const char *path = "/data/media/photo.jpg";
if (access(path, R_OK) != 0) {
    fprintf(stderr, "input not readable: %s\n", strerror(errno));
    return -1;
}
int ret = system("jpegtran /data/media/photo.jpg -outfile out.jpg");
Defensive patterns

Strategy: validation

Validate before calling

#include <unistd.h>
// validate input file before invoking jpegtran
int validate_jpeg_input(const char *path) {
    if (access(path, R_OK) != 0) return -1;
    struct stat st;
    if (stat(path, &st) != 0) return -1;
    if (!S_ISREG(st.st_mode)) return -1;
    if (st.st_size < 2) return -1; // too small to be a JPEG
    return 0;
}

Try / catch

// Shell wrapper: check exit code after jpegtran
jpegtran "$input" -outfile "$output"
rc=$?
if [ $rc -ne 0 ]; then
    echo "jpegtran failed (exit $rc)" >&2
    exit $rc
fi

Prevention

When it happens

Trigger: Passing a non-existent file path, a path to a directory instead of a JPEG, a file with restrictive permissions (mode 000 or owned by another user), or a path containing a typo or stale reference.

Common situations: Hardcoded path in a JNI wrapper points to a file that was deleted or moved. Path with spaces not quoted in a shell invocation. File is in an Android content URI or sandboxed directory inaccessible to the native process. A relative path resolves against the wrong working directory.

Related errors


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