{"record":{"id":"f40485449a9cbc54","repo":"jackwener/OpenCLI","slug":"status-status-not-in-task-statuses-join-f40485","errorCode":null,"errorMessage":"status \"${status}\" not in {${TASK_STATUSES.join('|')}}","messagePattern":"status \"(.+?)\" not in (.+?)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-list.js","lineNumber":40,"sourceCode":"  name: 'task-list',\n  access: 'read',\n  description: 'List tasks (chat tasks = messages with task fields) attached to a channel. Optional --status filter.',\n  domain: SLOCK_DOMAIN,\n  strategy: Strategy.COOKIE,\n  browser: true,\n  siteSession: 'persistent',\n  args: [\n    { name: 'channel', positional: true, required: true, help: 'channelId UUID or #name' },\n    { name: 'status', help: `Filter by status: ${TASK_STATUSES.join('|')}` },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['id', 'taskNumber', 'title', 'taskStatus', 'assigneeId'],\n  func: async (page, kwargs) => {\n    const channel = String(kwargs.channel ?? '').trim();\n    if (!channel) throw new ArgumentError('channel required');\n    const status = kwargs.status ? String(kwargs.status).trim() : '';\n    if (status && !TASK_STATUSES.includes(status)) {\n      throw new ArgumentError(`status \"${status}\" not in {${TASK_STATUSES.join('|')}}`);\n    }\n    await page.goto(SLOCK_HOME_URL);\n    const snippet = `\n      ${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}\n      ${channelResolveFragment(channel)}\n      const status = ${JSON.stringify(status)};\n      const qs = status ? ('?status=' + encodeURIComponent(status)) : '';\n      const tres = await fetch('${SLOCK_API_BASE}/tasks/channel/' + encodeURIComponent(channelId) + qs, { credentials:'include', headers });\n      if (!tres.ok) return { kind: tres.status===401?'auth':'http', status: tres.status, where: '/tasks/channel/:id' };\n      const data = await tres.json();\n      // Server contract: { tasks: [...] }. Reject anything else as drift.\n      if (!data || !Array.isArray(data.tasks)) {\n        return { kind: 'http', status: 200, where: '/tasks/channel/:id (expected {tasks:[]}, got drift)' };\n      }\n      return { kind: 'ok', rows: data.tasks };\n    `;\n    const result = await page.evaluate(`(async () => { ${snippet} })()`);\n    const rows = dispatchEvaluateResult(result);","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-list.js#L22-L58","documentation":"In task-list, the optional --status flag is validated against the TASK_STATUSES allowlist after the channel check. Any provided value not exactly matching a canonical status (after trim) throws an ArgumentError enumerating the valid values, avoiding a guaranteed-400 request.","triggerScenarios":"Running `slock task-list --channel <ch> --status <value>` where value is not a member of TASK_STATUSES — wrong casing, alias tokens ('doing', 'wip'), typos, or values copied from other tools.","commonSituations":"Guessing the status vocabulary; case drift ('Open' vs 'open'); stale scripts written against an older status set that was later renamed; interpolating user input without validation.","solutions":["Check `slock task-list --help` and use exactly one of the listed statuses","Normalize the value (lowercase/underscore) to match the canonical tokens","Omit --status to list all and filter client-side","Validate user-supplied status in your wrapper script against the same TASK_STATUSES list"],"exampleFix":"// before\nawait cli('slock', 'task-list', '--channel', 'general', '--status', 'Closed');\n// after\nawait cli('slock', 'task-list', '--channel', 'general', '--status', 'closed'); // exact member","handlingStrategy":"validation","validationCode":"import { TASK_STATUSES } from 'clis/slock/task-statuses.js';\nif (status && !TASK_STATUSES.includes(status.trim())) {\n  throw new Error(`status must be one of: ${TASK_STATUSES.join('|')}`);\n}","typeGuard":"const isValidStatus = (s) => s == null || TASK_STATUSES.includes(String(s).trim());","tryCatchPattern":null,"preventionTips":["Use --help to confirm the canonical status strings","Normalize casing before passing --status","Validate user input against TASK_STATUSES in wrapper scripts"],"tags":["argument-validation","enum-validation","cli-input"],"backgroundTag":"invalid-enum-value","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}