{"record":{"id":"dbb4b52adf6efa91","repo":"jackwener/OpenCLI","slug":"target-required-channel-channel-threadshort","errorCode":null,"errorMessage":"target required: \"#channel\", \"#channel:threadShortId\", \"dm:@name\", \"dm:<userId>\", or channelId UUID.","messagePattern":"target required: \"#channel\", \"#channel:threadShortId\", \"dm:@name\", \"dm:<userId>\", or channelId UUID\\.","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/resolve.js","lineNumber":21,"sourceCode":"export const UUID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;\n\n// ThreadTarget shape: { parentTarget: string, parentMsgId: string }\nexport function classifyThreadTarget(raw) {\n  const s = String(raw ?? '').trim();\n  const m = s.match(/^(#?[^:]+):([A-Za-z0-9-]{6,})$/);\n  if (!m) return null;\n  return { parentTarget: m[1], parentMsgId: m[2] };\n}\n\n// Target kinds:\n//   { kind: 'channel-uuid', channelId }\n//   { kind: 'channel-name', name }\n//   { kind: 'dm-uuid', userId }\n//   { kind: 'dm-name', name }\n//   { kind: 'thread', parentTarget, parentMsgId }\nexport function classifyTarget(raw) {\n  const v = String(raw ?? '').trim();\n  if (!v) throw new ArgumentError('target required: \"#channel\", \"#channel:threadShortId\", \"dm:@name\", \"dm:<userId>\", or channelId UUID.');\n  if (v.startsWith('dm:')) {\n    const rest = v.slice(3);\n    if (!rest) throw new ArgumentError('dm target must be \"dm:<userId>\" or \"dm:@name\".');\n    if (UUID_RE.test(rest)) return { kind: 'dm-uuid', userId: rest };\n    if (rest.startsWith('@')) return { kind: 'dm-name', name: rest.slice(1) };\n    throw new ArgumentError('dm target must be \"dm:<userId-uuid>\" or \"dm:@name\".');\n  }\n  const tt = classifyThreadTarget(v);\n  if (tt) return { kind: 'thread', ...tt };\n  if (UUID_RE.test(v)) return { kind: 'channel-uuid', channelId: v };\n  return { kind: 'channel-name', name: v.replace(/^#/, '').toLowerCase() };\n}\n\nconst SHORT_ID_HINT =\n  'short ids (the 8-hex `msg=...` form in channel headers) are NOT accepted — use the FULL UUID ' +\n  'from `bookmark-list` / `message-read` output.';\n\nexport function assertMessageIdShape(messageId) {","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/resolve.js#L3-L39","documentation":"classifyTarget parses the positional `target` argument for Slock commands; when the value is empty after trimming, it throws this ArgumentError listing all accepted target forms. The command cannot resolve a channel, DM, or thread without a target string.","triggerScenarios":"Calling a command that classifies its target (e.g. message-send) with an empty positional: `slock message-send \"\" \"hello\"`, or a kwargs.target that is undefined/null coerced to '' via `String(raw ?? '')`.","commonSituations":"Script variable for the channel unset; quoting mistake passing an empty string; piping empty input into the target slot; calling the CLI programmatically and omitting kwargs.target.","solutions":["Provide a valid target: `#channel`, `#channel:threadId`, `dm:@name`, `dm:<userId-uuid>`, or a channel UUID","Check the script/variable that supplies the target is not empty","Quote the target in the shell: `slock message-send \"#general\" \"hi\"`"],"exampleFix":"// before\nawait cli('message-send', { target: '', content: 'hi' });\n// after\nawait cli('message-send', { target: '#general', content: 'hi' });","handlingStrategy":"validation","validationCode":"const target = String(process.argv[2] ?? '').trim();\nif (!target) throw new Error('target required: \"#channel\", \"#channel:threadId\", \"dm:@name\", \"dm:<userId>\", or channelId UUID');","typeGuard":"function isValidTarget(v) {\n  if (typeof v !== 'string') return false;\n  const s = v.trim();\n  if (!s) return false;\n  if (s.startsWith('dm:')) return s.length > 3;\n  return /^#/.test(s) || /^[0-9a-fA-F-]{6,}$/.test(s);\n}","tryCatchPattern":"try {\n  await cli('message-send', { target, content });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.startsWith('target required')) {\n    console.error('No target given; supply #channel, dm:@name, dm:<uuid>, or a channel UUID.');\n  } else throw e;\n}","preventionTips":["Check that the variable supplying the target is non-empty before invoking","Quote target arguments in the shell so empty values are visible","For programmatic use, fail early on falsy targets with a clear message","Keep target formats documented next to script entry points"],"tags":["argument-validation","missing-argument","target-parsing"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}