{"record":{"id":"b83717fe0db3b7f7","repo":"kovidgoyal/kitty","slug":"refusing-to-read-image-file-as-permission-was-deni","errorCode":null,"errorMessage":"Refusing to read image file as permission was denied","messagePattern":"Refusing to read image file as permission was denied","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kitty/graphics.c","lineNumber":708,"sourceCode":"                load_data->loading_for = (const ImageAndFrame){0};\n            }\n            break;\n        case 'f': // file\n        case 't': // temporary file\n        case 's': // POSIX shared memory\n            if (g->payload_sz > 2048) ABRT(\"EINVAL\", \"Filename too long\");\n            snprintf(fname, sizeof(fname) / sizeof(fname[0]), \"%.*s\", (int)g->payload_sz, payload);\n            if (transmission_type == 's') fd = safe_shm_open(fname, O_RDONLY, 0);\n            else fd = safe_open(fname, O_CLOEXEC | O_RDONLY | O_NONBLOCK, 0); // O_NONBLOCK so that opening a FIFO pipe does not block\n            if (fd == -1) ABRT(\"EBADF\", \"Failed to open file for graphics transmission with error: [%d] %s\", errno, strerror(errno));\n            if (global_state.boss && transmission_type != 's') {\n                RAII_PyObject(cret_, PyObject_CallMethod(global_state.boss, \"is_ok_to_read_image_file\", \"si\", fname, fd));\n                if (cret_ == NULL) {\n                    PyErr_Print();\n                    ABRT(\"EBADF\", \"Failed to check file for read permission\");\n                }\n                if (cret_ != Py_True) {\n                    log_error(\"Refusing to read image file as permission was denied\");\n                    ABRT(\"EPERM\", \"Permission denied to read image file\");\n                }\n            }\n            // When the data needs further processing the entire (possibly\n            // compressed) payload is needed, otherwise reading more than the\n            // expected number of bytes is pointless.\n            const size_t max_to_read = (g->compressed || data_fmt == PNG) ? MAX_DATA_SZ : load_data->data_sz;\n            load_data->loading_completed_successfully = read_img_file(self, fd, g->data_sz, g->data_offset, max_to_read, transmission_type == 's');\n            safe_close(fd, __FILE__, __LINE__);\n            if (transmission_type == 't' && strstr(fname, \"tty-graphics-protocol\") != NULL) {\n                if (global_state.boss) {\n                    call_boss(safe_delete_temp_file, \"s\", fname);\n                } else unlink(fname);\n            } else if (transmission_type == 's') shm_unlink(fname);\n            if (!load_data->loading_completed_successfully) return NULL;\n            break;\n        default: ABRT(\"EINVAL\", \"Unknown transmission type: %c\", g->transmission_type);\n    }","sourceCodeStart":690,"sourceCodeEnd":726,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kitty/graphics.c#L690-L726","documentation":"kitty refused to transmit an image file because the Python-side is_ok_to_read_image_file check returned non-True - the user declined the permission prompt or the allow-list denied the file. The graphics command is aborted with EPERM.","triggerScenarios":"Sending a graphics protocol transmit-file command (t=t) whose path fails kitty's file-read permission policy (ask/deny configuration).","commonSituations":"An app or kitten displays an image from a path outside allowed directories; the user answered 'no' to the read-permission prompt; file-read allow list too restrictive.","solutions":["Answer 'yes' or 'always' when kitty asks permission to read the file","Add the directory to kitty's file-read allow list in the permission prompt or kitty.conf","Verify the path is readable by the kitty process","For scripting, pre-approve directories via the permissions config instead of relying on the prompt"],"exampleFix":"# kitty.conf\n# before (default: ask)\n# after\nallow_file_read /home/user/Pictures","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-approve image directories in kitty's file permissions config","When scripting graphics transmission, check for the EPERM abort code in the terminal response"],"tags":["kitty","graphics-protocol","permissions","eperm"],"backgroundTag":"permission-denied","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}