{"record":{"id":"fe55c18378aaab1e","repo":"apache/superset","slug":"theme-mode-changes-are-not-allowed-when-only-one-t","errorCode":null,"errorMessage":"Theme mode changes are not allowed when only one theme is available","messagePattern":"Theme mode changes are not allowed when only one theme is available","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"superset-frontend/src/theme/ThemeController.ts","lineNumber":871,"sourceCode":"    }\n  }\n\n  /**\n   * Validates permission to update theme.\n   */\n  private validateThemeUpdatePermission(): void {\n    if (!this.canSetTheme())\n      throw new Error('User does not have permission to update the theme');\n  }\n\n  /**\n   * Validates permission to update mode.\n   * @throws {Error} If the user does not have permission to update the theme mode\n   */\n  private validateModeUpdatePermission(): void {\n    // Check if user can set a new theme mode (dark theme must exist)\n    if (!this.canSetMode())\n      throw new Error(\n        'Theme mode changes are not allowed when only one theme is available',\n      );\n  }\n\n  /**\n   * Applies the current theme configuration to the global theme.\n   * This method sets the theme on the globalTheme and applies it to the Theme.\n   * It also handles any errors that may occur during the application of the theme.\n   * @param theme - The theme configuration to apply (may already include base theme tokens)\n   */\n  private applyTheme(theme: AnyThemeConfig): void {\n    try {\n      const normalizedConfig = normalizeThemeConfig(theme);\n\n      // Simply apply the theme - it should already be properly merged if needed\n      // The merging with base theme happens in getThemeForMode() and other methods\n      // that prepare themes before passing them to applyTheme()\n      this.globalTheme.setConfig(normalizedConfig);","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset-frontend/src/theme/ThemeController.ts#L853-L889","documentation":"ThemeController.validateModeUpdatePermission throws when canSetMode() is false, which happens when no dark theme is available — with only a single (light) theme there is nothing to switch modes between, so 'dark'/'system' mode requests are rejected. The message names exactly this condition.","triggerScenarios":"Calling setMode('dark') or setMode('system') when the ThemeController was initialized without a darkTheme; embedded host sends setThemeMode while the deployment only registered a light theme.","commonSituations":"Custom theme packages that only ship a light variant; feature flag/config disabling dark theme; upgrading Superset where the dark theme token file moved and the custom theme no longer resolves it.","solutions":["Provide a dark theme variant to the ThemeController so both modes exist.","Only expose a mode switcher in the UI when themeController.canSetMode() is true.","In embedded hosts, check canSetMode() before posting setThemeMode over the Switchboard.","If dark mode was intentionally disabled, stop sending mode-change requests."],"exampleFix":"// before\nthemeController.setMode('dark');\n\n// after\nif (!themeController.canSetMode()) {\n  logging.warn('Mode changes disabled: no dark theme available');\n  return;\n}\nthemeController.setMode('dark');","handlingStrategy":"validation","validationCode":"if (!themeController.canSetMode()) {\n  // no dark theme available; keep mode controls hidden\n  return;\n}\nthemeController.setMode(mode);","typeGuard":"type ThemeMode = 'default' | 'dark' | 'system';\n\nfunction isThemeMode(v: unknown): v is ThemeMode {\n  return v === 'default' || v === 'dark' || v === 'system';\n}","tryCatchPattern":"try {\n  themeController.setMode(mode);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('only one theme')) {\n    logging.warn('Dark theme missing; mode change ignored');\n    return;\n  }\n  throw e;\n}","preventionTips":["Ship a dark theme variant whenever the product exposes a mode switcher.","Conditionally render the light/dark toggle on canSetMode().","Test custom theme packages against both modes before deploying."],"tags":["theme","dark-mode","theming","embedded"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}