kovidgoyal/kitty · error

Could not open controlling terminal with error: %w

Error message

Could not open controlling terminal with error: %w

What it means

The wcswidth kitten could not open the controlling terminal (tty.OpenControllingTerm failed). It needs direct tty access to write test sequences and read cursor position reports, so without it the kitten cannot run.

Source

Thrown at tools/cli/wcswidth_kitten.go:221

		for _, grapheme := range t.Data {
			buf.WriteString(grapheme + cursor_position_report)
			pos += wcswidth.Stringwidth(grapheme)
			expected_cursor_positions = append(expected_cursor_positions, 1+pos)
		}
		test := test_struct{num: len(tests) + 1, description: desc, payload: buf.String(), expected_cursor_positions: expected_cursor_positions}
		tests = append(tests, &test)
	}
	test := test_struct{
		num: len(tests) + 1, description: "Check that combining characters are merged into last cell even when cursor is on the next line",
		payload_gen: wrap_gen, tester: wrap_tester}
	tests = append(tests, &test)
	return
}

func main(allowed_tests *utils.Set[int]) (rc int, err error) {
	term, err := tty.OpenControllingTerm()
	if err != nil {
		return 1, fmt.Errorf("Could not open controlling terminal with error: %w", err)
	}
	sz, err := term.GetSize()
	term.Close()
	if err != nil {
		return 1, fmt.Errorf("Could not get size of controlling terminal with error: %w", err)
	}
	width_in_cells := int(sz.Col)
	if gb_tests, err := kitty.LoadGraphemeBreakTests(); err == nil {
		tests := create_tests(gb_tests, width_in_cells)
		if allowed_tests.Len() > 0 {
			temp := make([]*test_struct, 0, len(tests))
			for _, t := range tests {
				if allowed_tests.Has(t.num) {
					temp = append(temp, t)
				}
			}
			tests = temp
		}

View on GitHub (pinned to 6d5d0c4406)

Solutions

  1. Run the command from an interactive terminal session
  2. If over ssh, use 'ssh -t' to force pty allocation
  3. Avoid redirecting stdin/stdout of the kitten
  4. Run it inside the kitty terminal itself
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.OpenFile("/dev/tty", os.O_RDWR, 0); err != nil { /* abort before running the kitten */ }

Try / catch

if rc, err := main(allowed); err != nil { fmt.Fprintln(os.Stderr, err); os.Exit(rc) }

Prevention

When it happens

Trigger: Invoking the kitten in an environment with no controlling terminal: piped stdin/stdout, a cron job, CI, or a pty that has been closed.

Common situations: Running kitty +kitten wcswidth via ssh with no tty allocation (missing -t), redirecting output to a file, running from a script without a terminal, or executing inside CI containers.

Related errors


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