kovidgoyal/kitty · error
Failed to decode PNG image at: %s with error: %s
Error message
Failed to decode PNG image at: %s with error: %s
What it means
png_from_data failed to decode a PNG: the zlib inflate or libpng read pipeline reported an error (captured in d.error.buf). It is logged with the path/data source given by the caller (window icon, background image, or window logo), and the function returns false so the caller falls back to defaults.
Source
Thrown at kitty/graphics.c:514
}
static void
print_png_read_error(png_read_data *d, const char *code, const char *msg) {
if (d->error.used >= d->error.capacity) {
size_t cap = MAX(2 * d->error.capacity, 1024 + d->error.used);
d->error.buf = realloc(d->error.buf, cap);
if (!d->error.buf) return;
d->error.capacity = cap;
}
d->error.used += snprintf(d->error.buf + d->error.used, d->error.capacity - d->error.used, "%s: %s ", code, msg);
}
bool
png_from_data(void *png_data, size_t png_data_sz, const char *path_for_error_messages, uint8_t **data, unsigned int *width, unsigned int *height, size_t *sz) {
png_read_data d = {.err_handler = print_png_read_error};
inflate_png_inner(&d, png_data, png_data_sz, MAX_IMAGE_DIMENSION);
if (!d.ok) {
log_error("Failed to decode PNG image at: %s with error: %s", path_for_error_messages, d.error.used > 0 ? d.error.buf : "");
free(d.decompressed);
free(d.row_pointers);
free(d.error.buf);
return false;
}
*data = d.decompressed;
free(d.row_pointers);
free(d.error.buf);
*sz = d.sz;
*height = d.height;
*width = d.width;
return true;
}
bool
png_from_file_pointer(FILE *fp, const char *path_for_error_messages, uint8_t **data, unsigned int *width, unsigned int *height, size_t *sz) {
size_t capacity = 16 * 1024, pos = 0;
unsigned char *buf = malloc(capacity);View on GitHub (pinned to 6d5d0c4406)
Solutions
- Validate the image is a real PNG: file icon.png (or pngcheck icon.png)
- Re-export/re-download the image; open it in an image editor and re-save as PNG
- Resize the image below kitty's MAX_IMAGE_DIMENSION
- If passing raw data programmatically, confirm you are passing PNG-encoded bytes, not decoded RGBA
Example fix
# before (kitty.conf) background_image ~/pics/photo.cwebp # after background_image ~/pics/photo.png
Defensive patterns
Strategy: validation
Validate before calling
import struct
def is_png(data: bytes) -> bool:
return len(data) >= 8 and data[:8] == b'\x89PNG\r\n\x1a\n'
# and: pngcheck file.png before configuring it Type guard
def is_valid_png(data: bytes) -> bool:
if not is_png(data):
return False
w, h = struct.unpack('>II', data[16:24])
return 0 < w <= MAX_IMAGE_DIMENSION and 0 < h <= MAX_IMAGE_DIMENSION Try / catch
if not png_from_data(buf, sz, path, &out, &w, &h, &osz) { /* keep default icon/background instead of failing */ } Prevention
- Run pngcheck on images before pointing kitty.conf at them
- Keep background images modest in dimensions (screen resolution)
- Re-save unusual PNGs (16-bit/CMYK) as standard 8-bit RGBA
When it happens
Trigger: Passing corrupt or non-PNG bytes to kitty's graphics API: set_os_window_icon with bad data, background_image config pointing to a truncated/corrupt PNG, or a window logo image that exceeds MAX_IMAGE_DIMENSION.
Common situations: background_image in kitty.conf pointing to a partially-downloaded or CMYK/16-bit-unusual PNG; icons damaged by transfer; images larger than kitty's MAX_IMAGE_DIMENSION limit; providing JPEG/WebP bytes where PNG is required.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- The PNG image: %s could not be opened with error: %s
- This must be run as kitten ask
- Out of memory reading PNG file at: %s
- Failed while reading from file: %s with error: %s
- Failed to convert image at %s to bitmap with python error:
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/55d53a5a93f5f3d0.
Report an issue: GitHub.