{"record":{"id":"2d668dfba69efbc7","repo":"koala73/worldmonitor","slug":"mission-preset-presetid-is-not-available-on-thi","errorCode":null,"errorMessage":"Mission preset ${presetId} is not available on this variant","messagePattern":"Mission preset (.+?) is not available on this variant","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/mission-presets.ts","lineNumber":451,"sourceCode":"\nexport function dismissMissionPresetPrompt(): void {\n  try {\n    localStorage.setItem(MISSION_PRESET_DISMISSED_KEY, '1');\n  } catch {\n    // Ignore storage failures.\n  }\n}\n\nexport function applyMissionPresetToState(\n  presetId: MissionPresetId,\n  currentPanelSettings: Record<string, PanelConfig>,\n  defaultLayers: MapLayers = DEFAULT_MAP_LAYERS,\n  variant: string = SITE_VARIANT,\n): AppliedMissionPreset {\n  const preset = getMissionPreset(presetId);\n  if (!preset) throw new Error(`Unknown mission preset: ${presetId}`);\n  if (!isMissionPresetAvailableForVariant(preset, variant)) {\n    throw new Error(`Mission preset ${presetId} is not available on this variant`);\n  }\n\n  const variantPanels = getVariantDefaultPanels(variant);\n  const variantPanelSet = new Set(variantPanels);\n  const matchingPresetPanels = preset.panels.filter((key) => key !== 'map' && variantPanelSet.has(key));\n  const useVariantDefaultPanels = matchingPresetPanels.length < MIN_PRESET_PANEL_MATCHES;\n  const selectedPanels = useVariantDefaultPanels\n    ? withMapPanel(variantPanels)\n    : preset.panels.filter((key) => key === 'map' || variantPanelSet.has(key));\n  const selectedPanelSet = new Set(selectedPanels);\n  const nextPanelSettings: Record<string, PanelConfig> = {};\n  const allKeys = new Set([\n    ...Object.keys(DEFAULT_PANELS),\n    ...Object.keys(ALL_PANELS),\n    ...Object.keys(currentPanelSettings),\n    ...selectedPanels,\n  ]);\n","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/koala73/worldmonitor/blob/9361220cc013571781071f0206e4d80fd14b2f7f/src/services/mission-presets.ts#L433-L469","documentation":"After the preset id resolves, applyMissionPresetToState checks isMissionPresetAvailableForVariant(preset, variant) and throws when the preset is gated off for the current site variant (e.g. a preset only shipped on the full site but requested on a minimal/region variant). The preset exists but is not licensed for this deployment variant.","triggerScenarios":"Calling applyMissionPresetToState/applyMissionPreset with a valid presetId whose availability list excludes the current SITE_VARIANT (or an explicitly passed variant string), e.g. forcing a variant-specific preset in a build where it is disabled.","commonSituations":"Hardcoding a preset id that exists on the main site but not on a stripped-down variant; passing the wrong variant argument; stored preset ids synced from another variant's localStorage; variant renamed in config while preset availability lists still use old names.","solutions":["Filter preset choices through isMissionPresetAvailableForVariant(preset, SITE_VARIANT) before applying.","Omit the variant argument to use the built-in SITE_VARIANT default instead of a mismatched literal.","Fall back to a universally available preset when the requested one is gated off for the variant.","Keep preset availability lists in sync when renaming or adding variants."],"exampleFix":"// before\napplyMissionPreset('maritime-ops', 'mobile-lite'); // not available on this variant\n// after\nconst preset = getMissionPreset('maritime-ops');\nif (preset && isMissionPresetAvailableForVariant(preset, SITE_VARIANT)) {\n  applyMissionPreset('maritime-ops');\n} else {\n  applyMissionPreset(DEFAULT_MISSION_PRESET_ID);\n}","handlingStrategy":"validation","validationCode":"import { getMissionPreset, isMissionPresetAvailableForVariant, SITE_VARIANT } from '../services/mission-presets';\nconst preset = getMissionPreset(presetId);\nif (!preset || !isMissionPresetAvailableForVariant(preset, SITE_VARIANT)) {\n  presetId = DEFAULT_MISSION_PRESET_ID;\n}\n","typeGuard":"function canApplyPreset(id: MissionPresetId, variant: string = SITE_VARIANT): boolean {\n  const p = getMissionPreset(id);\n  return !!p && isMissionPresetAvailableForVariant(p, variant);\n}\n","tryCatchPattern":"try {\n  applyMissionPreset(presetId);\n} catch (e) {\n  if (e instanceof Error && /is not available on this variant/.test(e.message)) {\n    applyMissionPreset(DEFAULT_MISSION_PRESET_ID);\n  } else throw e;\n}\n","preventionTips":["Gate preset menus through isMissionPresetAvailableForVariant so unavailable options are never offered","Let SITE_VARIANT be the default instead of passing literal variant strings","Keep preset availability lists updated when adding or renaming variants","Don't sync stored preset ids across variants without re-validating availability"],"tags":["validation","variant-gating","mission-presets","configuration"],"backgroundTag":"feature-unavailable-for-variant","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"}