theme: auto: OSC 11 detects light terminal, but syntax-highlighted code still renders with dark palette (white-on-white)
Summary
With theme: "auto" on a light-background terminal, Claude Code correctly detects "light" via OSC 11 (confirmed in the debug log) but still renders syntax-highlighted code blocks — Read/Write previews and diffs — with a dark palette whose default foreground is white. Result: plain identifiers, operators, and punctuation are white-on-white and unreadable. The UI chrome around the code is fine; only the highlighter is wrong.
Environment
- Claude Code 2.1.132
- macOS iTerm2 (light theme) → ssh → docker exec → tmux 3.5a → Claude Code
TERM=screen-256color(also reproduced withtmux-256color)COLORFGBGis unset inside the session (typical over ssh/tmux)~/.claude/settings.json:"theme": "auto"
Steps to reproduce
- Use a terminal with a light background where
COLORFGBGis not in the environment but OSC 11 (\e]11;?) works. The easy way to get there: ssh to a remote host and run inside tmux. (Should also reproduce locally in any terminal that doesn't exportCOLORFGBG.) - Confirm OSC 11 round-trips: send
\e]11;?\e\\in raw mode and verify argb:ffff/ffff/ffff-style reply. - Set
"theme": "auto". - Launch Claude Code and run anything that prints code — Read a file, Write a file, or make an edit that shows a diff.
Expected
Code blocks render with a light syntax palette: dark default foreground, readable identifiers and operators.
Actual
The breakage splits cleanly by token class. Anything with an explicit theme color is visible; anything that uses the default foreground is white-on-white:
| Visible (explicit color) | Invisible (default fg = white) |
|---|---|
| keywords (def, if, return) | plain identifiers (row, conn) |
| string literals | operators (=, +) |
| numbers, type annotations | punctuation ((, ), [, ], :, {) |
| constants (None) | line numbers in non-diff code blocks |
Diff blocks appear to work because the red/green line backgrounds make the white text visible — the bug only shows clearly on plain Read/Write output and on unchanged context lines inside diffs.
(Screenshots demonstrating the symptom — and the same block with text selected to reveal the invisible characters — to follow as a comment.)
Evidence that detection itself is correct
Debug log (~/.claude/debug/<session>.txt):
2026-05-06T23:00:15.031Z [DEBUG] systemTheme: OSC 11 response=rgb:ffff/ffff/ffff detected=light via=mux-bare
Claude Code asked, the terminal answered white, Claude Code computed light. The detection pipeline works end to end.
What looks broken
The OSC 11 result arrives asynchronously, after the first frame. When it does:
- The UI chrome updates to the light palette (headers, status text, etc. are readable).
- The syntax highlighter does not — code blocks rendered after detection still use the dark palette.
Two observations support this:
- Setting
"theme": "light"explicitly renders everything correctly. So the light highlighter palette is fine — it just isn't being selected when the resolution arrives via the async OSC 11 path. - If
COLORFGBGis present in the env (e.g. a local terminal that exports it),theme: "auto"works.COLORFGBGis read synchronously before the first render, so there's no dark→light transition and nothing for the highlighter to miss.
Likely related reports
This may account for the earlier reports that theme: "auto" "doesn't work in tmux" or "doesn't work in Alacritty" — both are environments where COLORFGBG is typically absent and OSC 11 is the only detection path. The detection isn't failing; the result just isn't reaching the syntax highlighter.
Workarounds
- Set
"theme": "light"(or"light-daltonized", etc.) explicitly. - Make
COLORFGBGavailable —SendEnv/AcceptEnv COLORFGBGover ssh,set -ag update-environment "COLORFGBG"in.tmux.conf— so detection happens synchronously at startup.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗