{"record":{"id":"a5d6a13bb5357256","repo":"NousResearch/hermes-agent","slug":"theme-is-missing-required-colors","errorCode":null,"errorMessage":"Theme is missing required colors.","messagePattern":"Theme is missing required colors\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/src/themes/user-themes.ts","lineNumber":96,"sourceCode":"function persist(record: Record<string, DesktopTheme>) {\n  try {\n    window.localStorage.setItem(USER_THEMES_KEY, JSON.stringify(record))\n  } catch {\n    // Best-effort: a restricted storage context shouldn't break theming.\n  }\n}\n\n/** Reactive map of installed user themes, keyed by slug. */\nexport const $userThemes = atom<Record<string, DesktopTheme>>(typeof window === 'undefined' ? {} : readStored())\n\n/** Install (or replace) a user theme. Returns the stored theme. */\nexport function installUserTheme(theme: DesktopTheme): DesktopTheme {\n  if (BUILTIN_THEMES[theme.name]) {\n    throw new Error(`\"${theme.name}\" collides with a built-in theme.`)\n  }\n\n  if (!isValidTheme(theme)) {\n    throw new Error('Theme is missing required colors.')\n  }\n\n  const next = { ...$userThemes.get(), [theme.name]: theme }\n  $userThemes.set(next)\n  persist(next)\n\n  return theme\n}\n\n/** Remove a user theme by slug. No-op for unknown / built-in names. */\nexport function removeUserTheme(name: string): void {\n  const current = $userThemes.get()\n\n  if (!current[name]) {\n    return\n  }\n\n  const next = { ...current }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/desktop/src/themes/user-themes.ts#L78-L114","documentation":"Thrown by installUserTheme when isValidTheme(theme) fails — the theme object lacks the required color entries. Before persisting to the $userThemes atom and localStorage, the installer verifies the theme carries the mandatory color palette; a structurally present but incomplete theme (missing key colors) is rejected.","triggerScenarios":"Calling installUserTheme with a hand-written or converted theme object whose colors map omits required keys — typically a VS Code conversion that produced an empty palette, or a partial JSON theme file.","commonSituations":"Installing a hand-edited theme JSON with truncated colors, or a theme built from a VS Code extension whose colors map was absent (upstream errors surface here if convertVscodeColorTheme's output is misused).","solutions":["Run isValidTheme(theme) yourself and log which required colors are missing before installing.","Fill in the missing required color fields in the theme JSON (backgrounds, foregrounds, accents per DesktopTheme's contract).","If the theme came from a VS Code conversion, re-check the source file actually has a 'colors' map."],"exampleFix":"// before\ninstallUserTheme(partialTheme)\n\n// after\nif (!isValidTheme(theme)) { /* report missing colors, then fix theme JSON */ }\ninstallUserTheme(theme)","handlingStrategy":"validation","validationCode":"import { isValidTheme } from '.../themes/user-themes'\n\nif (!isValidTheme(theme)) {\n  // list missing required colors and block install\n}","typeGuard":"function isCompleteTheme(t: unknown): t is DesktopTheme {\n  return isValidTheme(t as DesktopTheme)\n}","tryCatchPattern":"try {\n  installUserTheme(theme)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Theme is missing required colors.')\n    showValidationErrors(collectMissingColors(theme))\n  else throw e\n}","preventionTips":["Validate theme JSON against the DesktopTheme contract in an import wizard before install.","Run converters' output through isValidTheme in dev builds to catch upstream regressions.","Log which color keys are missing to make fixes mechanical."],"tags":["desktop","themes","validation","colors"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}