{"record":{"id":"003f44a5ed84f2f1","repo":"koala73/worldmonitor","slug":"invalid-variant","errorCode":"invalid_variant","errorMessage":"variant must be one of: full, tech, finance, commodity, energy, happy.","messagePattern":"variant must be one of: full, tech, finance, commodity, energy, happy\\.","errorType":"error_code","errorClass":"MissionPresetCatalogError","httpStatus":null,"severity":"error","filePath":"src/services/webmcp-mission-preset-catalog.ts","lineNumber":209,"sourceCode":"      }\n      : {\n        panelCount: 0,\n        layerCount: 0,\n      }),\n    active: live.activePresetId === preset.id,\n    monitorCompatible,\n    entitled,\n    available,\n    ...(reason ? { unavailableReason: reason } : {}),\n  };\n}\n\nexport function listMissionPresetCatalog(\n  live: MissionPresetCatalogLiveState,\n  query: MissionPresetCatalogQuery = {},\n): MissionPresetCatalogResult {\n  if (!isSiteVariant(live.variant)) {\n    throw new MissionPresetCatalogError(\n      'invalid_variant',\n      'variant must be one of: full, tech, finance, commodity, energy, happy.',\n    );\n  }\n  if (query.available !== undefined && typeof query.available !== 'boolean') {\n    throw new MissionPresetCatalogError(\n      'malformed_arguments',\n      'available must be a boolean.',\n    );\n  }\n\n  const presets = getMissionPresetsForVariant(live.variant)\n    .map((preset) => buildMissionPresetCatalogItem(preset.id, {\n      ...live,\n      variant: live.variant as SiteVariant,\n    }))\n    .filter((item) => (query.available === undefined ? true : item.available === query.available));\n","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/src/services/webmcp-mission-preset-catalog.ts#L191-L227","documentation":"listMissionPresetCatalog() reads live.variant from the caller-supplied MissionPresetCatalogLiveState and verifies it with isSiteVariant(). Because live.variant is typed as a plain string, an unrecognized variant string makes downstream variant-filtered preset lookups impossible, so the function throws MissionPresetCatalogError with reason 'invalid_variant'. Valid variants are: full, tech, finance, commodity, energy, happy.","triggerScenarios":"Passing a MissionPresetCatalogLiveState whose variant is not exactly one of 'full' | 'tech' | 'finance' | 'commodity' | 'energy' | 'happy' — e.g. 'prod', 'default', 'Full', an empty string, or undefined coerced to a string — when listMissionPresetCatalog is invoked (via listWebMcpMissionPresets).","commonSituations":"Constructing the live state from a URL query param, env var, or host-app setting with a different naming scheme than SITE_VARIANTS; a new variant added in the host app but not registered in @/config/variant; case-sensitive mismatch ('Tech' vs 'tech').","solutions":["Set live.variant to one of the SITE_VARIANTS values ('full','tech','finance','commodity','energy','happy'); check @/config/variant for the authoritative list.","Normalize the incoming value: trim and lowercase it, map legacy alias names to current variant ids before building the live state.","Run isSiteVariant(variant) on the value before constructing MissionPresetCatalogLiveState and fall back to VARIANT_DEFAULTS/default variant when false.","Catch MissionPresetCatalogError and inspect reason === 'invalid_variant' to surface the accepted variant list to the caller."],"exampleFix":"// before\nconst live = { variant: urlParams.get('variant') ?? '', hasPremium: false, activePresetId: null };\nlistMissionPresetCatalog(live);\n// after\nconst raw = urlParams.get('variant')?.toLowerCase() ?? '';\nif (!isSiteVariant(raw)) throw new Error(`unsupported variant: ${raw}`);\nlistMissionPresetCatalog({ ...live, variant: raw });","handlingStrategy":"validation","validationCode":"import { isSiteVariant } from '@/config/variant';\nif (!isSiteVariant(live.variant)) {\n  throw new Error(`variant must be one of full|tech|finance|commodity|energy|happy, got '${live.variant}'`);\n}","typeGuard":"function isKnownVariant(value: string): value is SiteVariant {\n  return isSiteVariant(value);\n}","tryCatchPattern":"try {\n  return listMissionPresetCatalog(live, query);\n} catch (err) {\n  if (err instanceof MissionPresetCatalogError && err.reason === 'invalid_variant') {\n    return listMissionPresetCatalog({ ...live, variant: DEFAULT_VARIANT }, query);\n  }\n  throw err;\n}","preventionTips":["Always run isSiteVariant() when building MissionPresetCatalogLiveState from strings.","Normalize case/whitespace and map legacy alias names to current SITE_VARIANTS ids.","Derive variant from a single source of truth (@/config/variant), not ad-hoc strings.","Add new variants to SITE_VARIANTS first; never invent variant ids at call sites."],"tags":["validation","variant","mission-presets","catalog"],"backgroundTag":"invalid-enum-value","analyzedSha":"9361220cc013571781071f0206e4d80fd14b2f7f","analyzedAt":"2026-09-01T10:32:37.851Z","contentChangedAt":"2026-09-01T10:32:37.851Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}