{"record":{"id":"a45cafa262fbfb0f","repo":"koala73/worldmonitor","slug":"unsupported-arxiv-category","errorCode":null,"errorMessage":"Unsupported arXiv category","messagePattern":"Unsupported arXiv category","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"server/worldmonitor/research/v1/list-arxiv-papers.ts","lineNumber":26,"sourceCode":"  ListArxivPapersRequest,\n  ListArxivPapersResponse,\n} from '../../../../src/generated/server/worldmonitor/research/v1/service_server';\n\nimport { ValidationError } from '../../../../src/generated/server/worldmonitor/research/v1/service_server';\nimport trackedCategories from '../../../../scripts/shared/research-arxiv-categories.json';\nimport { clampInt } from '../../../_shared/constants';\nimport { getCachedJson } from '../../../_shared/redis';\nimport { markNoStoreFallbackResponse } from '../../../_shared/response-headers';\n\nconst SEED_KEY_PREFIX = 'research:arxiv:v1';\n\nexport async function listArxivPapers(\n  ctx: ServerContext,\n  req: ListArxivPapersRequest,\n): Promise<ListArxivPapersResponse> {\n  const category = req.category || '';\n  if (category && !trackedCategories.includes(category)) {\n    throw new ValidationError([{ field: 'category', description: 'Unsupported arXiv category' }]);\n  }\n  const categories = category ? [category] : trackedCategories;\n  const pageSize = clampInt(req.pageSize, 50, 1, 100);\n  const snapshots = await Promise.all(categories.map(async (selected) => {\n    try {\n      return await getCachedJson(`${SEED_KEY_PREFIX}:${selected}::50`, true) as ListArxivPapersResponse | null;\n    } catch {\n      return null;\n    }\n  }));\n  const papers = new Map<string, ListArxivPapersResponse['papers'][number]>();\n  let incomplete = false;\n  for (const snapshot of snapshots) {\n    if (!Array.isArray(snapshot?.papers)) {\n      incomplete = true;\n      continue;\n    }\n    for (const paper of snapshot.papers) {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/server/worldmonitor/research/v1/list-arxiv-papers.ts#L8-L44","documentation":"listArxivPapers accepts an optional `category` filter and only serves categories the platform actively tracks. If the caller passes a category string that is not in the trackedCategories list, a ValidationError is thrown with field 'category'. This keeps cache seed keys (`arxiv:<category>`) bounded to known snapshots instead of doing uncached upstream arXiv fetches.","triggerScenarios":"Calling listArxivPapers with req.category set to a misspelled, renamed, or untracked arXiv category (e.g. 'cs.AI ' with whitespace, 'quant-ph' if not tracked, or an empty-but-truthy garbage string). Category must exactly match a member of trackedCategories.","commonSituations":"Developers guess arXiv taxonomy strings instead of copying them from the tracked list; a category was retired or renamed server-side; a client stores a stale category from an older API version; casing differs (arXiv categories are case-sensitive like 'cs.LG').","solutions":["List the supported categories by calling the endpoint with no category (it returns all trackedCategories) and pick one from the response","Fix the category string to match trackedCategories exactly, including casing and subject prefix (e.g. 'cs.LG', 'econ.EM')","Trim client input before sending; whitespace or empty-string handling differs from omission","If a needed category is genuinely missing, request it be added to trackedCategories rather than working around the error"],"exampleFix":"// before\nawait client.listArxivPapers({ category: 'cs.ml' });\n// after\nconst all = await client.listArxivPapers({});\nconst category = all.papers[0]?.category ?? 'cs.LG'; // use a tracked category\nawait client.listArxivPapers({ category });","handlingStrategy":"validation","validationCode":"const TRACKED = ['cs.LG','cs.AI','econ.EM']; // obtain from the unfiltered response\nif (category !== undefined && category !== '' && !TRACKED.includes(category)) {\n  throw new Error(`Unsupported arXiv category: ${category}`);\n}","typeGuard":"function isTrackedCategory(c: string): boolean {\n  return trackedCategories.includes(c);\n}","tryCatchPattern":"try {\n  return await client.listArxivPapers({ category });\n} catch (e) {\n  if (e instanceof ValidationError && e.fields?.[0]?.field === 'category') {\n    return client.listArxivPapers({}); // fall back to all tracked categories\n  }\n  throw e;\n}","preventionTips":["Source category choices from the API's own list, never free-text input","Keep categories case-exact (arXiv taxonomy is case-sensitive)","Trim user input before sending an optional filter"],"tags":["validation","api","arxiv","invalid-parameter"],"backgroundTag":"invalid-enum-value","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}