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
- Verify the file exists and is readable before invoking: `access(path, R_OK) == 0`
- Use an absolute path, not a relative one, especially when calling from JNI where cwd may differ
- Check file permissions: `ls -l <path>` and ensure the calling process has read access
- 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
- Always use absolute paths for input files in JNI contexts
- Call access(path, R_OK) before invoking jpegtran
- On Android, copy files from content URIs to internal storage before processing
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
- %s: can't open %s
- %s: can't determine size of %s
- %s: can't read ICC profile from %s
- %s: can't read from %s
- %s: can't read from stdin
AI-assisted analysis of DrKLO/Telegram@45ab8f4308 (2026-08-14).
Data as JSON: /api/errors/5c442c5f6de5c50f.
Report an issue: GitHub.