koala73/worldmonitor · error · ValidationError

scenarioId is required

Error message

scenarioId is required

What it means

Request validation in runScenario: req.scenarioId is empty after trim. The premium access check has already passed; the validation fails because no scenario template was named, so there is nothing to enqueue for the worker.

Solutions

  1. Pass a non-empty scenarioId from the scenario catalog
  2. Default the UI to a selected scenario so the field cannot be submitted blank
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/worldmonitor/scenario/v1/run-scenario.ts:36 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15). Data as JSON: /api/errors/24fccf2a269008b5. Report an issue: GitHub.

Appendix: source

Thrown at server/worldmonitor/scenario/v1/run-scenario.ts:36

function generateJobId(): string {
  const ts = Date.now();
  let suffix = '';
  const array = new Uint8Array(8);
  crypto.getRandomValues(array);
  for (const byte of array) suffix += JOB_ID_CHARSET[byte % JOB_ID_CHARSET.length];
  return `scenario:${ts}:${suffix}`;
}

export async function runScenario(
  ctx: ServerContext,
  req: RunScenarioRequest,
): Promise<RunScenarioResponse> {
  await requirePremiumRpcAccess(ctx.request, ApiError, 'PRO subscription required');

  const scenarioId = (req.scenarioId ?? '').trim();
  if (!scenarioId) {
    throw new ValidationError([{ field: 'scenarioId', description: 'scenarioId is required' }]);
  }
  const template = getScenarioTemplate(scenarioId);
  if (!template) {
    throw new ValidationError([{ field: 'scenarioId', description: `Unknown scenario: ${scenarioId}` }]);
  }

  const disruptionPct = req.disruptionPct;
  if (disruptionPct !== undefined && (
    !Number.isInteger(disruptionPct) || disruptionPct < 0 || disruptionPct > 100
    || template.affectedChokepointIds.length === 0
  )) {
    throw new ValidationError([{ field: 'disruptionPct', description: 'disruptionPct must be an integer from 0 to 100 for a physical scenario' }]);
  }

  const iso2 = req.iso2 ? req.iso2.trim() : '';
  if (iso2 && !/^[A-Z]{2}$/.test(iso2)) {
    throw new ValidationError([{ field: 'iso2', description: 'iso2 must be a 2-letter uppercase country code' }]);
  }

View on GitHub (pinned to 7d06c8633d)