koala73/worldmonitor · error · ValidationError
Unsupported arXiv category
Error message
Unsupported arXiv category
What it means
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.
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
Example fix
// before
await client.listArxivPapers({ category: 'cs.ml' });
// after
const all = await client.listArxivPapers({});
const category = all.papers[0]?.category ?? 'cs.LG'; // use a tracked category
await client.listArxivPapers({ category }); Defensive patterns
Strategy: validation
Validate before calling
const TRACKED = ['cs.LG','cs.AI','econ.EM']; // obtain from the unfiltered response
if (category !== undefined && category !== '' && !TRACKED.includes(category)) {
throw new Error(`Unsupported arXiv category: ${category}`);
} Type guard
function isTrackedCategory(c: string): boolean {
return trackedCategories.includes(c);
} Try / catch
try {
return await client.listArxivPapers({ category });
} catch (e) {
if (e instanceof ValidationError && e.fields?.[0]?.field === 'category') {
return client.listArxivPapers({}); // fall back to all tracked categories
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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').
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- hs4 must be a supported four-digit heading
- Invalid scorecard bloc selection.
- Expected an array of Sentry issues. A Sentry error body is a
- Sentry issues response was not an array
- Redis transaction failed: ${results?.error || 'invalid respo
AI-assisted analysis of koala73/worldmonitor@7d06c8633d (2026-09-15).
Data as JSON: /api/errors/a45cafa262fbfb0f.
Report an issue: GitHub.
Appendix: source
Thrown at server/worldmonitor/research/v1/list-arxiv-papers.ts:26
ListArxivPapersRequest,
ListArxivPapersResponse,
} from '../../../../src/generated/server/worldmonitor/research/v1/service_server';
import { ValidationError } from '../../../../src/generated/server/worldmonitor/research/v1/service_server';
import trackedCategories from '../../../../scripts/shared/research-arxiv-categories.json';
import { clampInt } from '../../../_shared/constants';
import { getCachedJson } from '../../../_shared/redis';
import { markNoStoreFallbackResponse } from '../../../_shared/response-headers';
const SEED_KEY_PREFIX = 'research:arxiv:v1';
export async function listArxivPapers(
ctx: ServerContext,
req: ListArxivPapersRequest,
): Promise<ListArxivPapersResponse> {
const category = req.category || '';
if (category && !trackedCategories.includes(category)) {
throw new ValidationError([{ field: 'category', description: 'Unsupported arXiv category' }]);
}
const categories = category ? [category] : trackedCategories;
const pageSize = clampInt(req.pageSize, 50, 1, 100);
const snapshots = await Promise.all(categories.map(async (selected) => {
try {
return await getCachedJson(`${SEED_KEY_PREFIX}:${selected}::50`, true) as ListArxivPapersResponse | null;
} catch {
return null;
}
}));
const papers = new Map<string, ListArxivPapersResponse['papers'][number]>();
let incomplete = false;
for (const snapshot of snapshots) {
if (!Array.isArray(snapshot?.papers)) {
incomplete = true;
continue;
}
for (const paper of snapshot.papers) {View on GitHub (pinned to 7d06c8633d)