{"record":{"id":"7dfe0570af8a8f3b","repo":"jackwener/OpenCLI","slug":"archive-search-sort-must-be-one-of-sort-options","errorCode":null,"errorMessage":"archive search sort must be one of ${SORT_OPTIONS.join(', ')}","messagePattern":"archive search sort must be one of (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/archive/search.js","lineNumber":33,"sourceCode":"    site: 'archive',\n    name: 'search',\n    access: 'read',\n    description: 'Search Internet Archive items across books, movies, audio, software, and web.',\n    domain: 'archive.org',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'query', positional: true, required: true, help: 'Full-text query (matches title, description, creator, subject).' },\n        { name: 'mediatype', type: 'string', required: false, help: `Restrict to mediatype: ${MEDIATYPES.join(', ')}` },\n        { name: 'sort', type: 'string', default: 'downloads', help: `Sort key: ${SORT_OPTIONS.join(', ')}` },\n        { name: 'limit', type: 'int', default: 20, help: 'Max items (max 100; one API page).' },\n    ],\n    columns: ['rank', 'identifier', 'title', 'creator', 'date', 'mediatype', 'downloads', 'url'],\n    func: async (args) => {\n        const sortRaw = String(args.sort ?? 'downloads').toLowerCase();\n        const sort = SORT_ALIAS[sortRaw] ?? sortRaw;\n        if (!SORT_OPTIONS.includes(sort)) {\n            throw new ArgumentError(`archive search sort must be one of ${SORT_OPTIONS.join(', ')}`);\n        }\n        if (args.mediatype && !MEDIATYPES.includes(String(args.mediatype))) {\n            throw new ArgumentError(`archive search mediatype must be one of ${MEDIATYPES.join(', ')}`);\n        }\n        const limit = Number(args.limit ?? 20);\n        if (!Number.isInteger(limit) || limit <= 0) {\n            throw new ArgumentError('archive search limit must be a positive integer');\n        }\n        if (limit > 100) {\n            throw new ArgumentError('archive search limit must be <= 100');\n        }\n\n        const query = String(args.query ?? '').trim();\n        if (!query) {\n            throw new ArgumentError('archive search query must not be empty');\n        }\n\n        const fullQuery = args.mediatype","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/archive/search.js#L15-L51","documentation":"This ArgumentError is thrown before any network call by `archive search` when the resolved `sort` value is not one of SORT_OPTIONS ('downloads', 'date', 'addeddate', 'week', 'title'). Input is lowercased and passed through SORT_ALIAS ('added'->'addeddate', 'published'->'date') first, so only values outside that whitelist fail. It is a client-side input validation error.","triggerScenarios":"Calling `opencli archive search <query> --sort <value>` where <value> (after lowercasing and alias mapping) is not exactly one of downloads, date, addeddate, week, title — e.g. --sort relevance, --sort pubdate, or a typo like --sort downlods.","commonSituations":"Copying sort keys from other search APIs (relevance, newest); using field names like 'year' or 'publisher' that archive.org supports in query syntax but are not whitelisted here; capitalization is fine (lowercased) but hyphenated variants like 'added-date' fail.","solutions":["Use one of the allowed values: downloads, date, addeddate, week, title","Use the built-in aliases: 'added' (for addeddate) or 'published' (for date)","Omit --sort entirely to get the default 'downloads' ordering"],"exampleFix":"// before\nopencli archive search \"folk songs\" --sort relevance\n// after\nopencli archive search \"folk songs\" --sort downloads","handlingStrategy":"validation","validationCode":"const SORT_OPTIONS = ['downloads', 'date', 'addeddate', 'week', 'title'];\nconst SORT_ALIAS = { added: 'addeddate', published: 'date' };\nconst sort = SORT_ALIAS[String(rawSort).toLowerCase()] ?? String(rawSort).toLowerCase();\nif (!SORT_OPTIONS.includes(sort)) throw new Error(`sort must be one of ${SORT_OPTIONS.join(', ')}`);","typeGuard":"const isSortOption = (s) => ['downloads','date','addeddate','week','title'].includes(s);","tryCatchPattern":"try {\n    rows = await run(['archive', 'search', query, '--sort', sort]);\n} catch (err) {\n    if (err instanceof ArgumentError && err.message.includes('sort must be one of')) {\n        rows = await run(['archive', 'search', query]); // fall back to default sort\n    } else { throw err; }\n}","preventionTips":["Whitelist sort values at the call site before invoking the CLI","Normalize user input with toLowerCase and the known aliases first","Omit --sort when unsure; the default 'downloads' is always valid","Keep the option list synced with the CLI's --help output"],"tags":["validation","cli","argument-error","input"],"backgroundTag":"invalid-argument-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}