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
- Pass the jobId exactly as returned by the runScenario response
- 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)