{"record":{"id":"c2967fea915b05d4","repo":"jackwener/OpenCLI","slug":"invalid-argument-c2967f","errorCode":"INVALID_ARGUMENT","errorMessage":"keyword is required","messagePattern":"keyword is required","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/51job/search.js","lineNumber":45,"sourceCode":"    browser: true,\n    navigateBefore: false,\n    args: [\n        { name: 'keyword', type: 'string', required: true, positional: true, help: '搜索关键词（岗位名 / 技能 / 公司）' },\n        { name: 'area', type: 'string', default: '全国', help: '城市名或 6 位城市码（如 \"杭州\" / \"080200\" / \"全国\"）' },\n        { name: 'salary', type: 'string', default: '', help: '薪资区间（如 \"10-15k\" / \"1-1.5万\" / \"20-30k\"）' },\n        { name: 'experience', type: 'string', default: '', help: '工作年限（如 \"应届\" / \"1-3年\" / \"3-5年\" / \"5-7年\"）' },\n        { name: 'degree', type: 'string', default: '', help: '学历要求（如 \"本科\" / \"大专\" / \"硕士\"）' },\n        { name: 'companyType', type: 'string', default: '', help: '公司性质（如 \"外资\" / \"国企\" / \"民营\"）' },\n        { name: 'companySize', type: 'string', default: '', help: '公司规模（如 \"50-150\" / \"1000-5000\"）' },\n        { name: 'sort', type: 'string', default: '综合', help: '排序：综合 / 最新 / 薪资 / 距离' },\n        { name: 'page', type: 'int', default: 1, help: '页码（1-based）' },\n        { name: 'limit', type: 'int', default: 20, help: '返回条数（1-50）' },\n    ],\n    columns: SEARCH_COLUMNS,\n    func: async (page, kwargs) => {\n        requirePage(page);\n        const keyword = String(kwargs.keyword ?? '').trim();\n        if (!keyword) throw new CliError('INVALID_ARGUMENT', 'keyword is required');\n        const limit = Math.max(1, Math.min(Number(kwargs.limit) || 20, 50));\n        const pageNum = Math.max(1, Number(kwargs.page) || 1);\n\n        const jobArea = resolveCity(kwargs.area);\n        const salary = resolveCode(kwargs.salary, SALARY_CODES);\n        const workYear = resolveCode(kwargs.experience, WORKYEAR_CODES);\n        const degree = resolveCode(kwargs.degree, DEGREE_CODES);\n        const companyType = resolveCode(kwargs.companyType, COMPANY_TYPE_CODES);\n        const companySize = resolveCode(kwargs.companySize, COMPANY_SIZE_CODES);\n        const sortType = resolveCode(kwargs.sort, SORT_CODES, '0');\n\n        // Establish WAF-clean origin. Reusing the same tab avoids the slider\n        // challenge fire every call.\n        const currentUrl = await page.evaluate(`(() => window.location.href)()`);\n        if (!String(currentUrl).startsWith(WE_ORIGIN)) {\n            await navigateTo(page, `${WE_ORIGIN}/pc/search?keyword=${encodeURIComponent(keyword)}&searchType=2`, 2);\n        }\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/51job/search.js#L27-L63","documentation":"The 51job search command requires a non-empty keyword; when kwargs.keyword is missing, null, or whitespace-only after trim, it throws CliError('INVALID_ARGUMENT') before any navigation. Pure client-side input validation.","triggerScenarios":"Calling the search subcommand without keyword, or with keyword: '' / undefined / '   ' (String(kwargs.keyword ?? '').trim() is empty) — thrown at clis/51job/search.js:45. Note: for keyword-less recommendations use the hot subcommand instead.","commonSituations":"Wiring search to a UI search box and submitting empty; config-driven runs where the keyword key is misspelled or unset; upstream pipeline dropping the term; intending hot-list behavior but calling search with no keyword.","solutions":["Provide a non-empty keyword string in the call","Trim/validate user input before invoking search","Use the hot subcommand if you want recommendations without a keyword","Fix the argument key name to exactly keyword"],"exampleFix":"// before\nawait cli.search({});\n// after\nconst kw = (input.term || '').trim();\nif (!kw) return cli.hot({}); // keyword-less → use hot\nreturn cli.search({ keyword: kw });","handlingStrategy":"validation","validationCode":"const keyword = String(input?.keyword ?? '').trim();\nif (!keyword) throw new Error('keyword must be a non-empty string before search');","typeGuard":"const hasKeyword = (a) => a != null && String(a.keyword ?? '').trim() !== '';","tryCatchPattern":"try {\n  return await cli.search({ keyword });\n} catch (e) {\n  if (e.code === 'INVALID_ARGUMENT') { console.warn('empty keyword'); return []; }\n  throw e;\n}","preventionTips":["Trim and check keyword before every search call","Route keyword-less use cases to the hot subcommand","Guard UI/config inputs so empty terms never reach the call","Use the exact argument name keyword"],"tags":["validation","invalid-argument","missing-parameter"],"backgroundTag":"missing-required-parameter","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}