{"record":{"id":"5c2d3a8dc07b89c3","repo":"kovidgoyal/kitty","slug":"failed-to-send-message-to-kitty-with-i-o-error-w","errorCode":null,"errorMessage":"Failed to send message to kitty with I/O error: %w","messagePattern":"Failed to send message to kitty with I/O error: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kittens/choose_fonts/backend.go","lineNumber":78,"sourceCode":"\t\tk.wait_for_exit <- k.cmd.Wait()\n\t}()\n\treturn\n}\n\nvar kitty_font_backend kitty_font_backend_type\n\nfunc (k *kitty_font_backend_type) send(v any) error {\n\tif k.to == nil {\n\t\treturn fmt.Errorf(\"Trying to send data when to pipe is nil\")\n\t}\n\tdata, err := json.Marshal(v)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Could not encode message to kitty with error: %w\", err)\n\t}\n\tc := make(chan error)\n\tgo func() {\n\t\tif _, err = k.to.Write(data); err != nil {\n\t\t\tc <- fmt.Errorf(\"Failed to send message to kitty with I/O error: %w\", err)\n\t\t\treturn\n\t\t}\n\t\tif _, err = k.to.Write([]byte{'\\n'}); err != nil {\n\t\t\tc <- fmt.Errorf(\"Failed to send message to kitty with I/O error: %w\", err)\n\t\t\treturn\n\t\t}\n\t\tc <- nil\n\t}()\n\tselect {\n\tcase err := <-c:\n\t\treturn err\n\tcase <-time.After(k.timeout):\n\t\treturn fmt.Errorf(\"Timed out waiting to write to kitty font backend after %v\", k.timeout)\n\tcase err := <-k.wait_for_exit:\n\t\tk.exited = true\n\t\tif err == nil {\n\t\t\terr = fmt.Errorf(\"kitty font backend exited with no error while waiting for a response from it\")\n\t\t} else {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/kittens/choose_fonts/backend.go#L60-L96","documentation":"Writing the JSON message body to the backend pipe returned an I/O error — typically EPIPE because the kitty subprocess died, or the pipe was closed concurrently. Raised inside the send goroutine.","triggerScenarios":"k.to.Write(data) fails after the '+runpy' kitty process exited (crash, kill, or normal shutdown racing a query).","commonSituations":"Backend python process crashed (import error in kittens.choose_fonts.backend); kitty was closed while a font query was in flight; pipe buffer closed early.","solutions":["Check k.stderr and process exit state to find why the backend died","Restart the backend (start()) and retry the query once","Verify the kitty executable and its kittens package are intact/consistent versions"],"exampleFix":"// before\nerr := backend.send(msg)\n// after\nif err := backend.send(msg); err != nil {\n    if strings.Contains(err.Error(), \"I/O error\") {\n        backend.restart(); err = backend.send(msg)\n    }\n}","handlingStrategy":"retry","validationCode":"if kitty_font_backend.cmd.ProcessState != nil && kitty_font_backend.cmd.ProcessState.Exited() { /* restart backend before sending */ }","typeGuard":null,"tryCatchPattern":"On write error, capture stderr, restart the backend via start(), and resend the message once; abort on second failure.","preventionTips":["Keep kitty and kittens versions consistent","Watch the backend process and log its stderr from the start"],"tags":["kitty","broken-pipe","io","choose-fonts"],"backgroundTag":"broken-pipe","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}