{"record":{"id":"75ba662ffd0acbec","repo":"jackwener/OpenCLI","slug":"messageid-raw-is-not-a-uuid-or-a-channel-sh","errorCode":null,"errorMessage":"messageId \"${raw}\" is not a UUID or a \"#channel:shortId\" form","messagePattern":"messageId \"(.+?)\" is not a UUID or a \"#channel:shortId\" form","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/task-convert.js","lineNumber":49,"sourceCode":"  browser: true,\n  siteSession: 'persistent',\n  args: [\n    { name: 'messageId', positional: true, required: true, help: 'Full message UUID, or \"#channel:shortId\" (short id expanded via /messages/context)' },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['id', 'taskNumber', 'title', 'taskStatus', 'channelId'],\n  func: async (page, kwargs) => {\n    const raw = String(kwargs.messageId ?? '').trim();\n    if (!raw) throw new ArgumentError('messageId required');\n\n    // Decide shape: bare UUID, or \"#channel:shortId\".\n    let resolveFragment;\n    if (UUID_RE.test(raw)) {\n      resolveFragment = `const fullMsgId = ${JSON.stringify(raw)};`;\n    } else {\n      const tt = classifyThreadTarget(raw);\n      if (!tt) {\n        throw new ArgumentError(`messageId \"${raw}\" is not a UUID or a \"#channel:shortId\" form`);\n      }\n      const isUuid = UUID_RE.test(tt.parentTarget);\n      const parent = JSON.stringify(tt.parentTarget.replace(/^#/, '').toLowerCase());\n      const pmsg = JSON.stringify(tt.parentMsgId);\n      // Phase 7.1 invariant baked in: we read cxd.targetMessageId, NOT\n      // m.message.id. The latter is the closest-message-in-context object,\n      // which can be a neighbor when the short id is just a prefix.\n      resolveFragment = `\n        let parentChannelId;\n        if (${isUuid}) {\n          parentChannelId = ${JSON.stringify(tt.parentTarget)};\n        } else {\n          const cres = await fetch('${SLOCK_API_BASE}/channels/', { credentials:'include', headers });\n          if (!cres.ok) return { kind: cres.status===401?'auth':'http', status: cres.status, where:'/channels/' };\n          const carr = await cres.json();\n          const hit = (Array.isArray(carr)?carr:(carr.channels||carr.data||[])).find((c) => (c.name||c.slug||'').toLowerCase() === ${parent});\n          if (!hit) return { kind: 'unresolvable', detail: 'no channel matches ' + ${parent} };\n          parentChannelId = hit.id;","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/task-convert.js#L31-L67","documentation":"task-convert accepts either a bare UUID or a '#channel:shortId' form; when the raw input matches neither, classifyThreadTarget returns null and an ArgumentError is thrown naming the offending input. This pre-flight validation runs before any browser/network work.","triggerScenarios":"Passing a short id without the '#channel:' prefix (e.g. '1234'), a URL instead of an id, a '#channel' reference missing the ':shortId' part, or arbitrary text like 'the pinned message'.","commonSituations":"Pasting a message permalink URL instead of the id; using the message number alone assuming it resolves; forgetting the '#channel:' prefix when only the short id is known.","solutions":["Use a full message UUID, or prefix the reference as '#channel:shortId' (e.g. '#general:1234').","Copy the id from the message's id column or context output rather than from a URL.","Strip any surrounding markup/URL — extract just the id portion before passing it."],"exampleFix":"// before\nslock task-convert 1234\n// after\nslock task-convert '#general:1234'","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst ok = UUID_RE.test(raw) || /^#[\\w-]+:\\d+$/.test(raw);\nif (!ok) throw new Error(`messageId must be a UUID or #channel:shortId, got: ${raw}`);","typeGuard":"const isValidMessageRef = (v) =>\n  typeof v === 'string' &&\n  (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v) || /^#[\\w-]+:\\d+$/.test(v));","tryCatchPattern":"try {\n  await cli('task-convert', raw);\n} catch (e) {\n  if (e instanceof ArgumentError && e.message.includes('not a UUID or a \"#channel:shortId\"')) {\n    console.error('Reformat input as a UUID or #channel:shortId, e.g. #general:1234');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Short ids must carry the '#channel:' prefix; build references programmatically as `#${channel}:${shortId}`.","Strip URL permalinks down to the bare id before passing.","Add a pre-flight regex check mirroring the CLI's accepted forms."],"tags":["cli","argument-format","input-validation"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}