{"record":{"id":"5179ae471126472e","repo":"jackwener/OpenCLI","slug":"dm-target-must-be-dm-userid-uuid-or-dm-name","errorCode":null,"errorMessage":"dm target must be \"dm:<userId-uuid>\" or \"dm:@name\".","messagePattern":"dm target must be \"dm:<userId-uuid>\" or \"dm:@name\"\\.","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/resolve.js","lineNumber":27,"sourceCode":"  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) {\n  const v = String(messageId ?? '').trim();\n  if (!v) throw new ArgumentError('messageId required');\n  if (!UUID_RE.test(v)) {\n    throw new ArgumentError(`messageId \"${v}\" is not a full UUID. ${SHORT_ID_HINT}`);\n  }\n  return v;","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/resolve.js#L9-L45","documentation":"When the target is `dm:<something>` where the remainder is neither a UUID nor an @name, classifyTarget throws this ArgumentError. Valid forms after `dm:` are a full user UUID or a name beginning with `@`.","triggerScenarios":"Passing `dm:alice` (no @ prefix), `dm:@` (bare @), `dm:#channel`, or `dm:<partial-uuid>` — anything where `UUID_RE.test(rest)` fails and `rest.startsWith('@')` is false.","commonSituations":"Writing `dm:jane` out of habit from other chat tools instead of `dm:@jane`; pasting a display name with spaces; using a short/incorrect user id that isn't a UUID; forgetting the @ in automation scripts.","solutions":["Prefix usernames with @: `dm:@jane`","Or use the user's full UUID: `dm:123e4567-e89b-12d3-a456-426614174000`","Validate the recipient format before invoking the command"],"exampleFix":"// before\n$ slock message-send dm:jane \"hello\"\n// after\n$ slock message-send dm:@jane \"hello\"","handlingStrategy":"validation","validationCode":"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}$/;\nconst t = String(target ?? '').trim();\nif (t.startsWith('dm:') && !UUID_RE.test(t.slice(3)) && !t.slice(3).startsWith('@')) {\n  throw new Error(`dm target must be \"dm:<userId-uuid>\" or \"dm:@name\", got \"${t}\"`);\n}","typeGuard":"function isValidDmTarget(v) {\n  if (typeof v !== 'string' || !v.startsWith('dm:')) return false;\n  const rest = v.slice(3);\n  return rest.startsWith('@') ||\n    /^[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}$/.test(rest);\n}","tryCatchPattern":"try {\n  await cli('message-send', { target, content });\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('dm:<userId-uuid>')) {\n    console.error(`\"${target}\" is not a valid dm form; prefix the username with @ or pass the user UUID.`);\n  } else throw e;\n}","preventionTips":["Always write usernames as dm:@name, never bare dm:name","For UUID form, use the full 36-char user UUID","Normalize user inputs (add the @ if missing) before passing targets on","Add a lint/check step in scripts that validates target syntax"],"tags":["argument-validation","target-parsing","dm"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}