{"record":{"id":"6dacc6db1585aab9","repo":"jackwener/OpenCLI","slug":"channel-required-uuid-or-name-server-rejects-u","errorCode":null,"errorMessage":"channel required (UUID or #name); server rejects uploads without channelId","messagePattern":"channel required \\(UUID or #name\\); server rejects uploads without channelId","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/attachment-upload.js","lineNumber":52,"sourceCode":"  site: SLOCK_SITE,\n  name: 'attachment-upload',\n  access: 'write',\n  description: 'Upload a local file to Slock attachments. Prints the attachmentId for use with `message-send --attach`.',\n  domain: SLOCK_DOMAIN,\n  strategy: Strategy.COOKIE,\n  browser: true,\n  siteSession: 'persistent',\n  args: [\n    { name: 'file', positional: true, required: true, help: 'Local file path to upload (single file; max 50 MB)' },\n    { name: 'channel', positional: true, required: true, help: 'channelId UUID or #name — server requires the attachment be scoped to a channel' },\n    { name: 'server', help: 'Override active server slug' },\n  ],\n  columns: ['attachmentId', 'filename', 'mimeType', 'sizeBytes'],\n  func: async (page, kwargs) => {\n    const filePath = String(kwargs.file ?? '').trim();\n    if (!filePath) throw new ArgumentError('file path required');\n    const channel = String(kwargs.channel ?? '').trim();\n    if (!channel) throw new ArgumentError('channel required (UUID or #name); server rejects uploads without channelId');\n    const abs = path.resolve(filePath);\n    let stat;\n    try { stat = fs.statSync(abs); }\n    catch (e) { throw new ArgumentError(`file not readable: ${abs} (${e.message})`); }\n    if (!stat.isFile()) throw new ArgumentError(`not a regular file: ${abs}`);\n    if (stat.size === 0) throw new ArgumentError(`file is empty: ${abs}`);\n    if (stat.size > MAX_BYTES) {\n      throw new ArgumentError(`file is ${stat.size} bytes, exceeds server limit ${MAX_BYTES} (50 MiB). Split or compress before upload.`);\n    }\n\n    const buf = fs.readFileSync(abs);\n    const filename = path.basename(abs);\n    const b64 = buf.toString('base64');\n\n    await page.goto(SLOCK_HOME_URL);\n\n    const snippet = `\n      ${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/attachment-upload.js#L34-L70","documentation":"This ArgumentError is thrown by `attachment-upload` in clis/slock/attachment-upload.js:52 when the `channel` argument is missing or blank. The Slock server requires every attachment upload to be scoped to a channel — the command appends `channelId` as a multipart part and the server returns 400 'channelId is required' without it — so the CLI validates the argument locally before doing any upload work.","triggerScenarios":"Running `attachment-upload ./file.png` without the second positional argument, or passing an empty/whitespace-only channel value. Scripts that omit the channel positional while only passing `--server` also hit this.","commonSituations":"Users assume the channel is inferred from context or configured elsewhere; automation templates omit the channel when adapting message-send invocations to attachment-upload; channel argument dropped when reordering positional arguments in a script.","solutions":["Provide the channel as the second positional argument: `attachment-upload ./file.png #general` or with the channel UUID.","If you only have a channel name, use the `#name` form — the command resolves it in-page to a UUID via channelResolveFragment.","Retrieve the channelId from a prior channel-list command and pass it explicitly in scripts."],"exampleFix":"// before: missing channel argument\nattachment-upload ./incident-log.zip\n// after: scope the upload to a channel (name or UUID)\nattachment-upload ./incident-log.zip \"#incident-reports\"","handlingStrategy":"validation","validationCode":"const channel = String(process.argv[3] ?? '').trim();\nif (!channel) {\n  throw new Error('channel required: pass a channelId UUID or #name as the second argument');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await upload({ file, channel });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('channel required')) {\n    console.error('Usage: attachment-upload <file> <channelId|#name>');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always pass a channel (UUID or `#name`) with every attachment upload — the server hard-requires channelId.","Store the target channel per environment in your script config so it is never omitted.","Resolve channel names to UUIDs once with a channel-list command and reuse the UUID in automation."],"tags":["argument-error","missing-argument","channel","validation"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}