{"record":{"id":"78f16d213f65e8fa","repo":"jackwener/OpenCLI","slug":"definition-arg-must-be-one-of-object-keys","errorCode":null,"errorMessage":"--${definition.arg} must be one of: ${Object.keys(definition.options).join(', ')}, got ${JSON.stringify(value)}","messagePattern":"--(.+?) must be one of: (.+?), got (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/search.js","lineNumber":340,"sourceCode":"    return result;\n}\nexport function parseLimit(raw) {\n    const parsed = Number(raw ?? 20);\n    if (!Number.isFinite(parsed) || !Number.isInteger(parsed)) {\n        throw new ArgumentError(`--limit must be an integer between 1 and 100, got ${JSON.stringify(raw)}`);\n    }\n    if (parsed < 1 || parsed > 100) {\n        throw new ArgumentError(`--limit must be between 1 and 100, got ${parsed}`);\n    }\n    return parsed;\n}\n\nfunction resolveSearchFilters(kwargs) {\n    return SEARCH_FILTERS.map((definition) => {\n        const value = kwargs[definition.arg] ?? definition.defaultValue;\n        const option = typeof value === 'string' ? definition.options[value] : undefined;\n        if (!option) {\n            throw new ArgumentError(\n                `--${definition.arg} must be one of: ${Object.keys(definition.options).join(', ')}, got ${JSON.stringify(value)}`,\n            );\n        }\n        return {\n            group: definition.group,\n            option,\n            capability: value === definition.defaultValue\n                ? ''\n                : definition.arg === 'location'\n                    ? 'location'\n                    : definition.arg === 'scope'\n                        ? 'account'\n                        : '',\n        };\n    });\n}\n\nfunction buildApplySearchFiltersJs(requestedFilters) {","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/search.js#L322-L358","documentation":"resolveSearchFilters maps each declared search filter (sort, note type, publish time, etc.) from its CLI argument value to a UI option defined in SEARCH_FILTERS. If the provided value is not a string or is not a key of definition.options, this ArgumentError is thrown listing all valid options. It is a strict allowlist check on filter argument values.","triggerScenarios":"Passing an unrecognized value to a filter flag, e.g. --sort newest2 or --note-type video|image, or passing a non-string value (number, object) programmatically into kwargs for a filter argument.","commonSituations":"Typos in filter values, guessing option names instead of checking the allowed list in the error message, version drift where option keys were renamed in a newer release, or scripts passing booleans/numbers where strings are expected.","solutions":["Use exactly one of the options listed in the error message (they are the Object.keys of definition.options)","Check SEARCH_FILTERS in clis/xiaohongshu/search.js for the current canonical option keys after upgrading","Convert programmatic values to their string key before passing (e.g. String(value))","Trim/lowercase user input if the option keys are case-sensitive and the source may include whitespace"],"exampleFix":"// before\n--sort \"Most Recent\"\n// after\n--sort \"newest\"   // one of the keys listed in the error","handlingStrategy":"validation","validationCode":"const ALLOWED_SORT = ['general', 'newest', 'hottest']; // mirror SEARCH_FILTERS keys\nif (!ALLOWED_SORT.includes(sortArg)) {\n  throw new Error(`--sort must be one of: ${ALLOWED_SORT.join(', ')}, got ${JSON.stringify(sortArg)}`);\n}","typeGuard":"const isFilterOption = (value, options) =>\n  typeof value === 'string' && Object.prototype.hasOwnProperty.call(options, value);","tryCatchPattern":"try {\n  filters = resolveSearchFilters(kwargs);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('--')) {\n    console.error(e.message); // message already lists valid options\n    process.exitCode = 1;\n  } else throw e;\n}","preventionTips":["Copy filter option keys directly from SEARCH_FILTERS instead of guessing","Trim and normalize user input to match case-sensitive option keys","Re-check option keys after upgrading the library (keys can be renamed)","Keep a mapping layer between your app's enum values and the CLI's option keys"],"tags":["cli","argument-validation","allowlist","filters"],"backgroundTag":"invalid-enum-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}