koala73/worldmonitor · error · ValidationError

Invalid or missing jobId

Error message

Invalid or missing jobId

What it means

Request validation in getScenarioStatus: req.jobId does not match the JOB_ID_RE pattern (scenario:<timestamp>:<random-suffix> as generated by runScenario's generateJobId). A malformed or missing id is rejected before the premium access check proceeds to any cache read.

Solutions

  1. Pass the jobId exactly as returned by the runScenario response
  2. Do not construct or truncate job ids client-side
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/worldmonitor/scenario/v1/get-scenario-status.ts:70 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-08-21). Data as JSON: /api/errors/2ef8e0e930941d7f. Report an issue: GitHub.

Appendix: source

Thrown at server/worldmonitor/scenario/v1/get-scenario-status.ts:131

    manifestFetchedAt: typeof c.manifestFetchedAt === 'string' ? c.manifestFetchedAt : '',
    records: records.map(r => ({
      iso2: r.iso2, hs2: r.hs2, state: r.state,
      basis: r.state === 'evaluated' ? String(r.basis) : '',
      rawImpact: r.state === 'evaluated' ? Number(r.rawImpact) : undefined,
      fetchedAt: typeof r.fetchedAt === 'string' ? r.fetchedAt : '',
    })),
  };
}

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

  const jobId = req.jobId ?? '';
  if (!JOB_ID_RE.test(jobId)) {
    throw new ValidationError([{ field: 'jobId', description: 'Invalid or missing jobId' }]);
  }

  // Worker writes under the raw (unprefixed) key, so we must read raw.
  let envelope: WorkerResultEnvelope | null = null;
  try {
    envelope = await getRawJson(`scenario-result:${jobId}`) as WorkerResultEnvelope | null;
  } catch {
    throw new ApiError(502, 'Failed to fetch job status', '');
  }

  if (!envelope) {
    return { status: 'pending', error: '' };
  }

  const status = typeof envelope.status === 'string' ? envelope.status : 'pending';

  if (status === 'done') {
    const result = coerceResult(envelope.result);

View on GitHub (pinned to 7d06c8633d)