kovidgoyal/kitty · warning

poll() on talk fds failed

Error message

poll() on talk fds failed

What it means

perror emitted when poll() over the 'talk' file descriptors (kitty's internal peer/remote-control IPC sockets) returns a negative value that is not EAGAIN or EINTR. This means the multiplexed IPC event loop in child-monitor.c could not wait on its sockets, usually due to a bad/stale fd or EBADF/EFAULT after a peer died. kitty logs it and continues; it indicates IPC plumbing trouble rather than a terminal failure.

Source

Thrown at kitty/child-monitor.c:2271

            for (size_t k = 0; k < talk_data.num_peers; k++) {
                Peer *p = talk_data.peers + k;
                if (p->fd_array_idx) {
                    if (fds[p->fd_array_idx].revents & POLLIN) read_from_peer(self, p);
                    if (fds[p->fd_array_idx].revents & POLLOUT) write_to_peer(p);
                    if (fds[p->fd_array_idx].revents & POLLHUP) {
                        // try to read and write nonetheless these functions will set the failed flags.
                        if (!p->read.finished) read_from_peer(self, p);
                        if (p->write.used) write_to_peer(p);
                    }
                    if (fds[p->fd_array_idx].revents & POLLNVAL) {
                        p->read.finished = true;
                        p->write.failed = true;
                        p->write.used = 0;
                    }
                }
            }
        } else if (ret < 0) {
            if (errno != EAGAIN && errno != EINTR) perror("poll() on talk fds failed");
        }
    }
end:
    free_loop_data(&talk_data.loop_data);
    for (size_t i = 0; i < talk_data.num_peers; i++) free_peer(talk_data.peers + i);
    free(talk_data.peers);
    return 0;
}

static void
send_response_to_peer(id_type peer_id, const char *msg, size_t msg_sz, bool is_async_response) {
    bool wakeup = false;
    talk_mutex(lock);
    for (size_t i = 0; i < talk_data.num_peers; i++) {
        Peer *peer = talk_data.peers + i;
        if (peer->id == peer_id) {
            peer->waiting_for_async_response = is_async_response;
            if (peer->num_of_unresponded_messages_sent_to_main_thread) peer->num_of_unresponded_messages_sent_to_main_thread--;

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Check dmesg/system logs for fd exhaustion; raise ulimit -n if the process is near its limit.
  2. Update kitty — stale-peer fd handling in the talk loop has been fixed in newer releases.
  3. Reproduce with KITTY_DEBUG / --debug-ipc if available and report the errno value printed after the message.
  4. If tied to a kitten, restart the kitten rather than the whole kitty session; the main loop recovers.
Defensive patterns

Strategy: fallback

Prevention

When it happens

Trigger: poll() returning -1 with errno such as EBADF (a closed talk fd still in the poll set), EFAULT (fds array out of reach), or ENOMEM, while running kitty with remote control (--listen-on), single-instance sockets, or peer kittens talking to the main process.

Common situations: A peer kitten or socket client crashes mid-connection leaving a stale fd; fd exhaustion on systems with many kittens/windows; bugs in older kitty versions where dead peer fds were not removed from the poll set.

Related errors


AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27). Data as JSON: /api/errors/afa2e9f92bff11c5. Report an issue: GitHub.