{"record":{"id":"811ea9fd9eba9fe3","repo":"jackwener/OpenCLI","slug":"title-required-non-empty","errorCode":null,"errorMessage":"title required (non-empty)","messagePattern":"title required \\(non-empty\\)","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-create.js","lineNumber":44,"sourceCode":"  name: 'task-create',\n  access: 'write',\n  description: 'Create a task in a channel (single title; batch 1-50 is server-supported but client surface is single — see backlog R4).',\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: 'title', positional: true, required: true, help: 'Task title (single; batch TODO via R4)' },\n    { name: 'desc', help: 'Optional description body for the task' },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['id', 'taskNumber', 'title', 'taskStatus', 'channelId'],\n  func: async (page, kwargs) => {\n    const channel = String(kwargs.channel ?? '').trim();\n    if (!channel) throw new ArgumentError('channel required');\n    const title = String(kwargs.title ?? '').trim();\n    if (!title) throw new ArgumentError('title required (non-empty)');\n    const desc = kwargs.desc != null ? String(kwargs.desc) : '';\n    await page.goto(SLOCK_HOME_URL);\n    const taskObj = desc ? { title, description: desc } : { title };\n    const snippet = `\n      ${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}\n      ${channelResolveFragment(channel)}\n      // Body is always a batch array — N=1 here because the CLI exposes one\n      // title at a time (R4 will widen this). Keep the wrapper so the server\n      // sees the same shape as a real batch and we don't fork the contract.\n      const body = { tasks: [${JSON.stringify(taskObj)}] };\n      const res = await fetch('${SLOCK_API_BASE}/tasks/channel/' + encodeURIComponent(channelId), {\n        method:'POST', credentials:'include', headers, body: JSON.stringify(body),\n      });\n      if (res.status === 400) {\n        const j = await res.json().catch(() => ({}));\n        return { kind: 'http', status: 400, where: '/tasks/channel/:id (bad request: ' + (j.error || j.message || 'title/limit/shape') + ')' };\n      }\n      if (res.status === 403) return { kind: 'http', status: 403, where: '/tasks/channel/:id (forbidden — channel archived or not a member)' };","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-create.js#L26-L62","documentation":"task-create requires a non-empty `title`; the func trims the value and throws ArgumentError when empty. Titles are mandatory because the backend task object is built from { title, description? }.","triggerScenarios":"Running task-create without --title, with --title \"\" or --title \"   \", or with quoting that collapses the value (e.g. --title $UNSET).","commonSituations":"Scripts building the command from variables where title is empty; unquoted shell variables losing whitespace-only titles; assuming a desc alone suffices.","solutions":["Pass --title with a non-empty string, quoted if it contains spaces.","Validate the title variable is non-empty before composing the command.","Always quote the flag value: --title \"My task title\"."],"exampleFix":"// before\nslock task-create --channel general --title $TITLE\n// after\nslock task-create --channel general --title \"${TITLE:?title required}\"","handlingStrategy":"validation","validationCode":"const title = String(opts.title ?? '').trim();\nif (!title) throw new Error('title must be a non-empty string');","typeGuard":"const hasTitle = (v) => typeof v === 'string' && v.trim().length > 0;","tryCatchPattern":"try {\n  await cli('task-create', ['--channel', channel, '--title', title]);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('title required')) {\n    console.error('Provide a non-empty --title value (quote it if it has spaces).');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always quote --title values in shell commands.","Trim and validate titles at the call site before invoking the CLI.","Never rely on desc alone; title is mandatory."],"tags":["cli","missing-argument","input-validation"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}