koala73/worldmonitor · error · MissionPresetCatalogError
invalid_variant
invalid_variant
Error message
variant must be one of: full, tech, finance, commodity, energy, happy.
What it means
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.
Source
Thrown at src/services/webmcp-mission-preset-catalog.ts:209
}
: {
panelCount: 0,
layerCount: 0,
}),
active: live.activePresetId === preset.id,
monitorCompatible,
entitled,
available,
...(reason ? { unavailableReason: reason } : {}),
};
}
export function listMissionPresetCatalog(
live: MissionPresetCatalogLiveState,
query: MissionPresetCatalogQuery = {},
): MissionPresetCatalogResult {
if (!isSiteVariant(live.variant)) {
throw new MissionPresetCatalogError(
'invalid_variant',
'variant must be one of: full, tech, finance, commodity, energy, happy.',
);
}
if (query.available !== undefined && typeof query.available !== 'boolean') {
throw new MissionPresetCatalogError(
'malformed_arguments',
'available must be a boolean.',
);
}
const presets = getMissionPresetsForVariant(live.variant)
.map((preset) => buildMissionPresetCatalogItem(preset.id, {
...live,
variant: live.variant as SiteVariant,
}))
.filter((item) => (query.available === undefined ? true : item.available === query.available));
View on GitHub (pinned to 9361220cc0)
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.
Example fix
// before
const live = { variant: urlParams.get('variant') ?? '', hasPremium: false, activePresetId: null };
listMissionPresetCatalog(live);
// after
const raw = urlParams.get('variant')?.toLowerCase() ?? '';
if (!isSiteVariant(raw)) throw new Error(`unsupported variant: ${raw}`);
listMissionPresetCatalog({ ...live, variant: raw }); Defensive patterns
Strategy: validation
Validate before calling
import { isSiteVariant } from '@/config/variant';
if (!isSiteVariant(live.variant)) {
throw new Error(`variant must be one of full|tech|finance|commodity|energy|happy, got '${live.variant}'`);
} Type guard
function isKnownVariant(value: string): value is SiteVariant {
return isSiteVariant(value);
} Try / catch
try {
return listMissionPresetCatalog(live, query);
} catch (err) {
if (err instanceof MissionPresetCatalogError && err.reason === 'invalid_variant') {
return listMissionPresetCatalog({ ...live, variant: DEFAULT_VARIANT }, query);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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').
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
- malformed_arguments
- Unknown mission preset: ${presetId}
- Mission preset ${presetId} is not available on this variant
- invalid_variant
- validation
AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01).
Data as JSON: /api/errors/003f44a5ed84f2f1.
Report an issue: GitHub.