kovidgoyal/kitty · info
Pending mode change to already current mode (%d) requested.
Error message
Pending mode change to already current mode (%d) requested. Either pending mode expired or there is an application bug.
What it means
An application toggled DEC private mode 2026 (pending/synchronized update mode) to the value already current - screen_pause_rendering returned false. Either the ~250ms pending window expired and the app re-issued the same change, or the app has a state bug. Rendering continues unsynchronized.
Source
Thrown at kitty/screen.c:2035
if (val) {
// When DECCOLM mode is set, the screen is erased and the cursor
// moves to the home position.
screen_erase_in_display(self, 2, false);
screen_cursor_position(self, 1, 1);
}
break;
case CONTROL_CURSOR_BLINK: self->cursor->non_blinking = !val; break;
case SAVE_CURSOR: screen_save_cursor(self); break;
case TOGGLE_ALT_SCREEN_1:
case TOGGLE_ALT_SCREEN_2:
case ALTERNATE_SCREEN:
if (val && self->linebuf == self->main_linebuf) screen_toggle_screen_buffer(self, mode == ALTERNATE_SCREEN, mode == ALTERNATE_SCREEN);
else if (!val && self->linebuf != self->main_linebuf) screen_toggle_screen_buffer(self, mode == ALTERNATE_SCREEN, mode == ALTERNATE_SCREEN);
break;
case 7727 << 5: log_error("Application escape mode is not supported, the extended keyboard protocol should be used instead"); break;
case PENDING_MODE << 5:
if (!screen_pause_rendering(self, val, 0)) {
log_error("Pending mode change to already current mode (%d) requested. Either pending mode expired or there is an application bug.", val);
}
break;
case INBAND_RESIZE_NOTIFICATION:
self->modes.mINBAND_RESIZE_NOTIFICATION = val;
if (val) CALLBACK("notify_child_of_resize", NULL);
break;
case VISIBILITY_REPORTS:
self->modes.mVISIBILITY_REPORTS = val;
if (val) send_visibility_report(self);
break;
default:
private = mode >= 1 << 5;
if (private) mode >>= 5;
log_error("%s %s %u %s", ERROR_PREFIX, "Unsupported screen mode: ", mode, private ? "(private)" : "");
}
#undef SIMPLE_MODE
#undef MOUSE_MODE
}View on GitHub (pinned to 6d5d0c4406)
Solutions
- Usually harmless - rendering continues without synchronization
- If you author the app, only send CSI ? 2026 l after a successful h
- Keep frame output under ~250ms so pending mode does not expire
- Update the app - duplicate-pending bugs get fixed over time
Example fix
# before printf '\033[?2026h'; printf '\033[?2026h' # duplicate begin # after printf '\033[?2026h' # begin once printf '\033[?2026l' # end once
Defensive patterns
Strategy: validation
Validate before calling
# track pending-mode state in your renderer
if not pending_active:
sys.stdout.write('\033[?2026h'); pending_active = True
# ... draw frame ...
sys.stdout.write('\033[?2026l'); pending_active = False Prevention
- Always pair 2026 h with exactly one 2026 l
- Keep frame output under ~250ms so pending mode does not expire
When it happens
Trigger: Program using synchronized output sends a duplicate CSI ? 2026 h (begin-begin) or an l after the pending period already expired.
Common situations: Frame-synchronization bugs in TUI apps, or slow rendering causing kitty's pending timeout to expire before the app ends the frame.
Related errors
- Application escape mode is not supported, the extended keybo
- %s %s %u %s
- This must be run as kitten ask
- This should be run as kitten broadcast
- This must be run as kitten choose-files
AI-assisted analysis of kovidgoyal/kitty@6d5d0c4406 (2026-08-27).
Data as JSON: /api/errors/2e10163948e71c93.
Report an issue: GitHub.