koala73/worldmonitor · error · ValidationError

chokepointId must be a canonical chokepoint id

Error message

chokepointId must be a canonical chokepoint id

What it means

getChokepointDependencies normalizes chokepointId to lowercase and requires it to match /^[a-z0-9_-]{1,80}$/ (a canonical chokepoint id like 'suez' or 'strait-of-hormuz'). Non-matching ids throw this ValidationError before any cache lookup.

Source

Thrown at server/worldmonitor/supply-chain/v1/get-chokepoint-dependencies.ts:31

  chokepointDependencyShardKey,
  resolvePageSize,
  enforceDependencyRedistributionPolicy,
  hasCurrentRedistributionPolicy,
  isMatchingShard,
  locateEntityShard,
  mapChokepointDependency,
  type RawVulnerabilityCohort,
  type RawChokepointShard,
  stringValue,
} from './_vulnerability-projection';

export async function getChokepointDependencies(
  ctx: ServerContext,
  req: GetChokepointDependenciesRequest,
): Promise<GetChokepointDependenciesResponse> {
  const chokepointId = (req.chokepointId || '').trim().toLowerCase();
  if (!/^[a-z0-9_-]{1,80}$/.test(chokepointId)) {
    throw new ValidationError([{ field: 'chokepointId', description: 'chokepointId must be a canonical chokepoint id' }]);
  }

  const persistedPayload = await getCachedJson(VULNERABILITY_COHORT_KEY, true)
    .catch(() => null) as RawVulnerabilityCohort | null;
  const payload = hasCurrentRedistributionPolicy(persistedPayload) ? persistedPayload : null;
  let chokepoint = payload?.chokepoints?.[chokepointId];
  let shardUnavailable = false;
  if (payload && !payload.chokepoints) {
    const located = locateEntityShard(
      payload,
      payload.chokepointIds,
      chokepointId,
      chokepointDependencyShardKey,
    );
    if (located.status === 'unavailable') {
      shardUnavailable = true;
    } else if (located.status === 'read') {
      const shard = await getCachedJson(located.key, true)

View on GitHub (pinned to 9361220cc0)

Solutions

  1. Use a canonical lowercase id (e.g. 'suez', 'panama', 'strait-of-hormuz') from the chokepoint seed/reference data
  2. Sanitize: trim, lowercase, replace spaces with '-' before calling
  3. Validate with /^[a-z0-9_-]{1,80}$/ on the client
  4. Check the chokepoint exists in the vulnerability cohort payload before calling

Example fix

// before
await getChokepointDependencies({ chokepointId: 'Suez Canal' })
// after
const id = String(raw).trim().toLowerCase().replace(/\s+/g, '-');
if (!/^[a-z0-9_-]{1,80}$/.test(id)) throw new Error('invalid chokepoint id');
await getChokepointDependencies({ chokepointId: id })
Defensive patterns

Strategy: validation

Validate before calling

function isValidChokepointId(v) {
  const id = String(v || '').trim().toLowerCase();
  return /^[a-z0-9_-]{1,80}$/.test(id);
}

Type guard

function isCanonicalChokepointId(v) {
  return typeof v === 'string' && /^[a-z0-9_-]{1,80}$/.test(v);
}

Try / catch

try {
  return await getChokepointDependencies({ chokepointId });
} catch (e) {
  if (e.name === 'ValidationError' && e.field === 'chokepointId') {
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing display names ('Suez Canal'), ids with spaces or special characters, empty/missing chokepointId, or ids longer than 80 characters.

Common situations: UI passing human-readable labels instead of canonical ids; ids sourced from free text; uppercase ids (regex is lowercase-only after toLowerCase, but non-ASCII or symbols fail); stale ids from an old seed dataset.

Related errors


AI-assisted analysis of koala73/worldmonitor@9361220cc0 (2026-09-01). Data as JSON: /api/errors/6f5d38cf8bfb8b6c. Report an issue: GitHub.