{"record":{"id":"58676f9d5f31f061","repo":"jackwener/OpenCLI","slug":"e-message-rethrown-as-argumenterror","errorCode":null,"errorMessage":"${e.message} (rethrown as ArgumentError)","messagePattern":"(.+?) \\(rethrown as ArgumentError\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-status.js","lineNumber":38,"sourceCode":"cli({\n  site: SLOCK_SITE,\n  name: 'task-status',\n  access: 'write',\n  description: `Set a task's status (PATCH /tasks/:taskId/status, body {status}). One of ${TASK_STATUSES.join('|')}.`,\n  domain: SLOCK_DOMAIN,\n  strategy: Strategy.COOKIE,\n  browser: true,\n  siteSession: 'persistent',\n  args: [\n    { name: 'taskId', positional: true, required: true, help: 'Full task UUID (= message id; short ids rejected)' },\n    { name: 'status', positional: true, required: true, help: `One of: ${TASK_STATUSES.join('|')}` },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['taskId', 'taskStatus', 'assigneeId', 'taskNumber'],\n  func: async (page, kwargs) => {\n    let id;\n    try { id = assertMessageIdShape(String(kwargs.taskId ?? '')); }\n    catch (e) { throw new ArgumentError(e.message); }\n    const status = String(kwargs.status ?? '').trim();\n    if (!TASK_STATUSES.includes(status)) {\n      throw new ArgumentError(`status \"${status}\" not in {${TASK_STATUSES.join('|')}} — pre-network reject (saves a 400 round-trip).`);\n    }\n    await page.goto(SLOCK_HOME_URL);\n    const snippet = `\n      ${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}\n      const res = await fetch('${SLOCK_API_BASE}/tasks/' + encodeURIComponent(${JSON.stringify(id)}) + '/status', {\n        method:'PATCH', credentials:'include', headers,\n        body: JSON.stringify({ status: ${JSON.stringify(status)} }),\n      });\n      if (res.status === 400) {\n        const j = await res.json().catch(() => ({}));\n        return { kind: 'http', status: 400, where: '/tasks/:taskId/status (bad request: ' + (j.error || j.message || 'invalid status transition') + ')' };\n      }\n      if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/:taskId/status (forbidden — terminal status (done/closed), not the assignee, or channel archived)' };\n      if (res.status === 404) return { kind: 'http', status: 404, where: '/tasks/:taskId/status (task not found)' };\n      // F6 — actionable hint for repeat-set 409 (\"status already X\").","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-status.js#L20-L56","documentation":"task-status validates --taskId with assertMessageIdShape and, on failure, rethrows the underlying message wrapped in an ArgumentError. The '(rethrown as ArgumentError)' suffix marks that the original shape-validation error was converted so callers can catch it uniformly as an argument error rather than an internal validation error.","triggerScenarios":"Running `slock task-status --taskId <value>` where value fails assertMessageIdShape — empty string, wrong length, non-id characters, or a taskNumber/integer passed where the message-id shape (uuid-like) is expected.","commonSituations":"Passing the numeric taskNumber instead of the task id; truncated copy-paste of the id; whitespace or quotes captured in the shell argument; unset variable yielding ''.}","solutions":["Copy the full task id exactly as shown by task-list output and re-run","Do not use the numeric taskNumber — fetch the id via `slock task-get --channel <ch> --number <n>`","Quote the argument in shell to avoid splitting/whitespace loss: --taskId \"$ID\"","Check the id against the expected shape (length/charset) before invoking"],"exampleFix":"// before\nawait cli('slock', 'task-status', '--taskId', '42'); // number, not id\n// after\nawait cli('slock', 'task-status', '--taskId', 'a1b2c3d4-e5f6-7890-abcd-ef1234567890');","handlingStrategy":"validation","validationCode":"const taskId = String(process.env.TASK_ID ?? '').trim();\nif (!/^[0-9a-f-]{16,}$/i.test(taskId)) {\n  throw new Error(`--taskId must be a full task id, got: \"${taskId}\"`);\n}","typeGuard":"const looksLikeTaskId = (v) => typeof v === 'string' && v.trim().length >= 16 && !/^\\d+$/.test(v.trim());","tryCatchPattern":"try {\n  await setTaskStatus(taskId, status);\n} catch (e) {\n  if (e.name === 'ArgumentError' && /rethrown as ArgumentError/.test(e.message)) {\n    // fetch the correct id via task-get before retrying\n  }\n  throw e;\n}","preventionTips":["Pass the full task id from task-list/task-get output, never the numeric taskNumber","Quote shell arguments to preserve the id exactly","Trim copied ids and re-check length after paste"],"tags":["argument-validation","id-shape","cli-input"],"backgroundTag":"invalid-argument-input","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}