{"record":{"id":"54de0ba6aaa2df65","repo":"jackwener/OpenCLI","slug":"invalid-argument-54de0b","errorCode":"INVALID_ARGUMENT","errorMessage":"jobId is required","messagePattern":"jobId is required","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/51job/detail.js","lineNumber":35,"sourceCode":"    description: '51job 职位详情（按 jobId）',\n    domain: 'jobs.51job.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    navigateBefore: false,\n    args: [\n        { name: 'jobId', type: 'string', required: true, positional: true, help: '职位 ID（search 返回的 jobId）' },\n    ],\n    columns: [\n        'jobId', 'title', 'salary', 'location', 'workYear', 'degree',\n        'category', 'address', 'ageRequirement',\n        'description', 'welfare',\n        'company', 'companyType', 'companySize', 'companyIndustry',\n        'companyUrl', 'url',\n    ],\n    func: async (page, kwargs) => {\n        requirePage(page);\n        const jobId = String(kwargs.jobId ?? '').trim();\n        if (!jobId) throw new CliError('INVALID_ARGUMENT', 'jobId is required');\n        if (!/^\\d{6,12}$/.test(jobId)) throw new CliError('INVALID_ARGUMENT', `jobId must be a 6-12 digit number, got \"${jobId}\"`);\n\n        const url = `${JOBS_ORIGIN}/x/${jobId}.html`;\n        await navigateTo(page, url, 2);\n\n        const script = `(() => {\n            const sel = s => document.querySelector(s)?.innerText?.trim() || '';\n            const all = s => [...document.querySelectorAll(s)].map(e => e.innerText.trim()).filter(Boolean);\n            const finalUrl = window.location.href;\n            const bodyText = (document.body.innerText || '').slice(0, 400);\n            if (/职位已下线|该职位已删除|页面不存在/.test(bodyText)) {\n                return { error: 'EXPIRED', bodyText };\n            }\n            const companyA = document.querySelector('.cname a, .tCompany_sidebar .com_msg a');\n            const funcs = all('.bmsg .fp');\n            const pick = (prefix) => {\n                const row = funcs.find(f => f.startsWith(prefix));\n                return row ? row.slice(prefix.length).replace(/^[:：\\\\s\\\\n]+/, '').trim() : '';","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/51job/detail.js#L17-L53","documentation":"The 51job job detail command validates that a jobId argument was supplied; when kwargs.jobId is missing, null, or an empty/whitespace string after trim, it throws CliError('INVALID_ARGUMENT'). This is an input-validation failure thrown synchronously before any navigation or network work.","triggerScenarios":"Calling the detail subcommand without jobId, or with jobId as undefined/null/'' (e.g. String(kwargs.jobId ?? '').trim() yields empty) — thrown at clis/51job/detail.js:35.","commonSituations":"Programmatic callers piping results where an upstream job item lacked an id; building the call from config where the jobId key is misspelled; passing a variable that is undefined due to a failed destructure.","solutions":["Pass a valid jobId string/number in the call arguments","Check the property name is exactly jobId (not id/jobID)","Guard upstream data: skip or log items without an id before calling detail","If ids come from a search result, ensure the mapping step copies the id field"],"exampleFix":"// before\nawait cli.detail({ id: job.id });\n// after\nif (!job.jobId) throw new Error('missing jobId for ' + job.title);\nawait cli.detail({ jobId: job.jobId });","handlingStrategy":"validation","validationCode":"const jobId = String(job?.jobId ?? '').trim();\nif (!jobId) throw new Error('jobId is required before calling detail');","typeGuard":"const hasJobId = (j) => j != null && String(j.jobId ?? '').trim() !== '';","tryCatchPattern":"try {\n  return await cli.detail({ jobId });\n} catch (e) {\n  if (e.code === 'INVALID_ARGUMENT') { console.warn('skip: missing jobId'); return null; }\n  throw e;\n}","preventionTips":["Always pass the argument key exactly as jobId","Filter out items lacking ids upstream","Typecheck call sites if using a typed wrapper","Never build kwargs dynamically without a presence check"],"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"}