Skip to content

openapi CLI stalls 5 s and emits a terminal colour query on every run when nothing answers OSC 11 (bubbletea v1 init-time probe) #250

Description

@david-long1

Summary

Every invocation of the openapi binary, including openapi --version, writes an OSC 11 background-colour query and a cursor-position request (ESC ] 11 ; ? ESC \ then ESC [ 6 n) to the terminal before doing anything else, then waits up to 5 s for a reply. In an interactive terminal the reply arrives immediately and is consumed. Under anything that hands the CLI a pseudo-terminal without relaying the reply, which is how pre-commit runners such as lefthook run hooks, the CLI blocks for the full timeout and the escape sequences land in the hook's captured output. When the real terminal does answer, the CLI never consumes the reply and it shows up as junk like 11;rgb:2424/2424/2424;1R in the shell.

This is not the CLI's own code. cmd/openapi/go.mod requires github.com/charmbracelet/bubbletea v1.3.10, and bubbletea v1's tea_init.go calls lipgloss.HasDarkBackground() from a package init(), so the query fires for any binary that links bubbletea, TUI or not. termenv's OSCTimeout is a hard-coded 5 s. Upstream tracked this as charmbracelet/bubbletea#1771 and closed it as not planned because v2 no longer queries at init.

Reproduction

macOS, TERM=xterm-256color, openapi built with go install github.com/speakeasy-api/openapi/cmd/openapi@latest (v0.0.0-20260826005500-83ebf39fa45e). script -q /dev/null ... gives the process a pty that nothing answers.

$ printf 'openapi: 3.1.0\ninfo:\n  title: t\n  version: "1"\npaths: {}\n' > spec.yaml

$ /usr/bin/time -p script -q /dev/null openapi spec lint spec.yaml < /dev/null | cat -v | head -1
^[]11;?^[\^[[6nLinting OpenAPI document: spec.yaml^M
real 5.02

$ CI=1 /usr/bin/time -p script -q /dev/null openapi spec lint spec.yaml < /dev/null | cat -v | head -1
Linting OpenAPI document: spec.yaml^M
real 0.02

$ /usr/bin/time -p script -q /dev/null openapi --version < /dev/null | cat -v
^[]11;?^[\^[[6nv0.0.0-20260826005500-83ebf39fa45e
real 5.02

CI=1 helps because termenv's isTTY() returns false whenever CI is set, which skips the query. From a lefthook pre-commit hook on the same machine I measured about 5.8 s with the reply leaking into the output, and 0.4 s with CI=1.

Expected

openapi spec lint and openapi --version don't touch the terminal or pay a timeout unless a TUI is actually about to start.

Suggested fix

The query runs at package init, before main(), so the CLI can't gate it on "is this really an interactive TTY" from its own code, and setting CI from inside the binary is too late as well. The options I see:

  1. Move to bubbletea v2 (with the matching lipgloss/huh releases). v2 doesn't query at init, which is why upstream closed #1771.
  2. Until then, document CI=1 as the escape hatch for pre-commit hooks and other non-interactive runs, since termenv already honours it.

Happy to send a PR for either once you say which way you'd like to go.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions