[Bug] Custom themes diff overrides not applying

Status Open
Reported on v2.1.132
Maintainer reply None cached
Activity 12 comments · opened May 7, 2026

Bug Description
Custom themes diff overrides not working

Environment Info

  • Platform: darwin
  • Terminal: iTerm.app
  • Version: 2.1.132
  • Feedback ID: 7e5b95f9-9a2a-4902-b02f-3155045e3ab3

<img width="446" height="325" alt="Image" src="https://github.com/user-attachments/assets/f5faddfc-2907-4be4-86d7-9694326081d8" />

<img width="937" height="487" alt="Image" src="https://github.com/user-attachments/assets/1b40990a-f671-4965-b5e3-892df7fc582a" />

When I create a custom theme with these values, it's not picking up all of my overrides.

{
    "name": "Rosé Pine",
    "base": "dark",
    "overrides": {
        "claude": "rgb(196,167,231)",
        "claudeShimmer": "rgb(235,188,186)",

        "text": "rgb(224,222,244)",
        "inverseText": "rgb(25,23,36)",
        "inactive": "rgb(110,106,134)",
        "inactiveShimmer": "rgb(144,140,170)",
        "subtle": "rgb(64,61,82)",
        "suggestion": "rgb(156,207,216)",
        "permission": "rgb(196,167,231)",
        "permissionShimmer": "rgb(235,188,186)",
        "remember": "rgb(235,188,186)",

        "success": "rgb(156,207,216)",
        "error": "rgb(235,111,146)",
        "warning": "rgb(246,193,119)",
        "warningShimmer": "rgb(250,215,160)",
        "merged": "rgb(196,167,231)",

        "promptBorder": "rgb(82,79,103)",
        "promptBorderShimmer": "rgb(144,140,170)",
        "planMode": "rgb(156,207,216)",
        "autoAccept": "rgb(49,116,143)",
        "bashBorder": "rgb(246,193,119)",
        "ide": "rgb(196,167,231)",
        "fastMode": "rgb(235,111,146)",
        "fastModeShimmer": "rgb(235,188,186)",

        "diffAdded": "rgb(40,82,96)",
        "diffRemoved": "rgb(102,42,70)",
        "diffAddedDimmed": "rgb(30,56,66)",
        "diffRemovedDimmed": "rgb(68,34,52)",
        "diffAddedWord": "rgb(64,128,152)",
        "diffRemovedWord": "rgb(235,111,146)",

        "userMessageBackground": "rgb(31,29,46)",
        "userMessageBackgroundHover": "rgb(38,35,58)",
        "messageActionsBackground": "rgb(64,61,82)",
        "bashMessageBackgroundColor": "rgb(38,35,58)",
        "memoryBackgroundColor": "rgb(38,35,58)",
        "selectionBg": "rgb(64,61,82)",

        "rate_limit_fill": "rgb(196,167,231)",
        "rate_limit_empty": "rgb(33,32,46)",
        "briefLabelYou": "rgb(156,207,216)",
        "briefLabelClaude": "rgb(196,167,231)",

        "red_FOR_SUBAGENTS_ONLY": "rgb(235,111,146)",
        "blue_FOR_SUBAGENTS_ONLY": "rgb(156,207,216)",
        "green_FOR_SUBAGENTS_ONLY": "rgb(49,116,143)",
        "yellow_FOR_SUBAGENTS_ONLY": "rgb(246,193,119)",
        "purple_FOR_SUBAGENTS_ONLY": "rgb(196,167,231)",
        "orange_FOR_SUBAGENTS_ONLY": "rgb(235,188,186)",
        "pink_FOR_SUBAGENTS_ONLY": "rgb(235,188,186)",
        "cyan_FOR_SUBAGENTS_ONLY": "rgb(156,207,216)"
    }
}

View original on GitHub ↗

9 Comments

ryanolson-dandy · 3 months ago

That diff screenshot was during testing the new theme

jw-y · 3 months ago

Having the same prob!

amzock · 3 months ago

same bug, confirming on a different setup:

  • Claude Code v2.1.140
  • Ghostty 1.3.1 (TERM=xterm-ghostty, COLORTERM=truecolor)
  • macOS Darwin 24.6.0

custom theme overrides for all 6 diff keys (diffAdded, diffAddedDimmed,
diffAddedWord, diffRemoved, diffRemovedDimmed, diffRemovedWord) silently
ignored. Other theme tokens (userMessageBackground, promptBorder, claude,
etc.) apply correctly from the same file.

another testing note: switching the theme's base from "dark" to
"light" DOES change the diff colors (to the built-in light defaults).

remigastaldi · 3 months ago

Confirming this on Linux with the latest release — the existing reports are all macOS, so adding a different platform/terminal as another data point.

Environment

  • Claude Code v2.1.156 (current latest)
  • Linux (CachyOS, kernel 7.0.5), Wayland / Hyprland
  • Running inside tmux: TERM=tmux-256color, COLORTERM=truecolor; verified true 24-bit RGB passes through (client_termfeatures includes RGB, setrgbf/setrgbb present)

Repro: custom theme at ~/.claude/themes/<slug>.json, selected via "theme": "custom:<slug>" in settings.json. All six diff overrides — diffAdded, diffRemoved, diffAddedWord, diffRemovedWord, diffAddedDimmed, diffRemovedDimmed — are silently ignored. Every other token in the same file (claude, text, userMessageBackground, promptBorder, success, error, …) applies correctly.

I double-checked the override values are well-formed and the keys are the documented ones; the diff simply renders with the base theme's built-in defaults instead of the overrides. This lines up with @amzock's note that flipping base dark↔light shifts the diff colors — to the built-in defaults, never to the custom values.

So this looks like a TUI logic bug independent of platform/terminal/truecolor: the diff-color path isn't wired to the custom-theme overrides. Still reproduces on the latest release (2.1.156).

mkouba · 2 months ago

I can still reproduce this issue with Claude Code v2.1.179, Linux 7.0.12-101.fc43.x86_64.

midgramr · 2 months ago

Still having this issue on Claude Code 2.1.186 on MacOS 26.5

gogongxt · 1 month ago

same issue with claudecode version 2.1.202

calebhearth · 1 month ago

Still present in v2.1.206 (macOS, Ghostty). I dug into the compiled binary and found the root cause; identifiers below are from the minified v2.1.206 bundle.

There are two token-resolution paths, and only one of them knows about custom themes:

  1. React theme context (healthy): the provider computes the active theme by merging the custom theme's overrides onto its base preset (C0i(EZ(base), overrides)). Anything rendered through this path — transcript +N/−N diff counters, dialog borders, labels — honors overrides correctly.
  1. Low-level color applier (buggy): a closure of the form

``js
function Yn(e, t, r = "foreground") {
return (n) => {
if (!e) return n;
if (e.startsWith("rgb(") || e.startsWith("#") || e.startsWith("ansi256(") || e.startsWith("ansi:"))
return p3e(n, e, r);
return p3e(n, EZ(t)[e], r); // ← token name resolved here
};
}
``

When e is a token name (e.g. diffAdded), it resolves via EZ(t), and EZ is a switch over only the six built-in presets:

``js
function EZ(e) { switch (e) {
case "light": ...; case "light-ansi": ...; case "dark-ansi": ...;
case "light-daltonized": ...; case "dark-daltonized": ...;
default: return K_h; // dark preset
}}
``

A custom:<slug> setting is at best normalized to the custom theme's base first (rq()getCustomThemeBase() || "dark"). The theme's overrides are never consulted on this path.

The Edit permission dialog's diff line backgrounds go through path 2, which explains both symptoms reported here: diff overrides are silently ignored, and changing the custom theme's base does change the diff colors (to that preset's stock values) — confirming the base is the only part of a custom theme this path sees.

Easy repro of the split: with a custom theme overriding diffAddedWord, trigger any file-edit permission prompt. The +N counter in the transcript uses the override while the word highlight inside the dialog's diff uses the base preset — same token, two colors.

Suggested fix: have path 2 resolve tokens against the same merged theme object the provider computes (or teach EZ to consult the loaded custom-theme cache), rather than mapping custom:* to a built-in preset.

Savageman · 1 month ago

I believe I found another yet-unmentioned repro condition: this only happens with syntax highlighting on (default) — pressing ctrl+t to disable it makes the custom diff overrides apply correctly, so highlighting is what selects the buggy path for diff line backgrounds.

Showing cached comments. Read the full discussion on GitHub ↗