koala73/worldmonitor · error · DashboardPanelCatalogError

invalid_variant

invalid_variant

Error message

variant must be one of: full, tech, finance, commodity, energy, happy.

What it means

listDashboardPanelCatalog() validates live.currentVariant with isSiteVariant() before enumerating panels. An unrecognized current variant makes variant-aware panel lookups (VARIANT_DEFAULTS, availability sets) impossible, so it throws DashboardPanelCatalogError with reason 'invalid_variant'. Acceptable values are full, tech, finance, commodity, energy, happy.

Source

Thrown at src/services/webmcp-panel-catalog.ts:142

export function getDashboardPanelCategoryKey(panelId: string, variant: string): string {
  for (const [key, definition] of Object.entries(PANEL_CATEGORY_MAP)) {
    if (definition.variants && !definition.variants.includes(variant)) continue;
    if (definition.panelKeys.includes(panelId)) return key;
  }
  for (const [key, definition] of Object.entries(PANEL_CATEGORY_MAP)) {
    if (definition.panelKeys.includes(panelId)) return key;
  }
  return 'other';
}

export function listDashboardPanelCatalog(
  live: DashboardPanelCatalogLiveState,
  query: DashboardPanelCatalogQuery = {},
): DashboardPanelCatalogPage {
  const currentVariant = live.currentVariant;
  if (!isSiteVariant(currentVariant)) {
    throw new DashboardPanelCatalogError(
      'invalid_variant',
      'variant must be one of: full, tech, finance, commodity, energy, happy.',
    );
  }

  const variantFilter = query.variant;
  if (variantFilter !== undefined) {
    if (typeof variantFilter !== 'string' || !isSiteVariant(variantFilter)) {
      throw new DashboardPanelCatalogError(
        'invalid_variant',
        'variant must be one of: full, tech, finance, commodity, energy, happy.',
      );
    }
  }

  const categoryFilter = query.category;
  if (categoryFilter !== undefined) {
    if (

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Ensure live.currentVariant is one of 'full','tech','finance','commodity','energy','happy'; consult @/config/variant for the source of truth.
  2. Normalize and validate with isSiteVariant() when constructing the live state; fall back to the default variant if invalid.
  3. Map legacy/alias variant names to current ids before the call.
  4. Catch DashboardPanelCatalogError with reason 'invalid_variant' to report the accepted variants back to the caller.

Example fix

// before
listDashboardPanelCatalog({ currentVariant: appConfig.variant, ... });
// after
const variant = isSiteVariant(appConfig.variant) ? appConfig.variant : VARIANT_DEFAULTS.defaultVariant;
listDashboardPanelCatalog({ currentVariant: variant, ... });
Defensive patterns

Strategy: validation

Validate before calling

import { isSiteVariant } from '@/config/variant';
if (!isSiteVariant(live.currentVariant)) {
  throw new Error(`currentVariant must be one of full|tech|finance|commodity|energy|happy, got '${live.currentVariant}'`);
}

Type guard

function hasValidCurrentVariant(live: DashboardPanelCatalogLiveState): live is DashboardPanelCatalogLiveState & { currentVariant: SiteVariant } {
  return isSiteVariant(live.currentVariant);
}

Try / catch

try {
  return listDashboardPanelCatalog(live, query);
} catch (err) {
  if (err instanceof DashboardPanelCatalogError && err.reason === 'invalid_variant') {
    return listDashboardPanelCatalog({ ...live, currentVariant: DEFAULT_VARIANT }, query);
  }
  throw err;
}

Prevention

When it happens

Trigger: Supplying a DashboardPanelCatalogLiveState whose currentVariant is not exactly one of the six SITE_VARIANTS — e.g. 'main', 'default', 'FULL', an empty string, or a stale value persisted before a variant rename — when listDashboardPanelCatalog runs (via listWebMcpDashboardPanels).

Common situations: currentVariant sourced from config, localStorage, or a hostname→variant mapping that drifted from SITE_VARIANTS; bootstrapping the dashboard before the variant is resolved; case mismatch after lowercasing was removed.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/ea639e42dfda493d. Report an issue: GitHub.