{"record":{"id":"26670ede091b1579","repo":"jackwener/OpenCLI","slug":"e-message","errorCode":null,"errorMessage":"${e.message}","messagePattern":"\\$\\{e\\.message\\}","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/bookmark-add.js","lineNumber":26,"sourceCode":"\ncli({\n  site: SLOCK_SITE,\n  name: 'bookmark-add',\n  access: 'write',\n  description: 'Bookmark a message (POST /channels/saved). Requires full messageId UUID.',\n  domain: SLOCK_DOMAIN,\n  strategy: Strategy.COOKIE,\n  browser: true,\n  siteSession: 'persistent',\n  args: [\n    { name: 'messageId', positional: true, required: true, help: 'Full messageId UUID (short ids rejected)' },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['messageId', 'saved'],\n  func: async (page, kwargs) => {\n    let id;\n    try { id = assertMessageIdShape(String(kwargs.messageId ?? '')); }\n    catch (e) { throw new ArgumentError(e.message); }\n    await page.goto(SLOCK_HOME_URL);\n    const snippet = `\n      ${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}\n      const res = await fetch('${SLOCK_API_BASE}/channels/saved', { method:'POST', credentials:'include', headers, body: JSON.stringify({ messageId: ${JSON.stringify(id)} }) });\n      if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/channels/saved' };\n      const data = await res.json().catch(() => ({}));\n      // F3-a — qatester live dump: response is { ok: true } with NO id field.\n      // The bookmark is keyed by messageId on the server side, so there is no\n      // separate bookmark id to surface; we report saved=true and echo the\n      // message id back.\n      return { kind: 'ok', rows: [{ saved: data && data.ok === true, messageId: ${JSON.stringify(id)} }] };\n    `;\n    const result = await page.evaluate(`(async () => { ${snippet} })()`);\n    const rows = dispatchEvaluateResult(result);\n    return rows.map((b) => ({ messageId: b.messageId ?? id, saved: b.saved === true }));\n  },\n});\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/bookmark-add.js#L8-L44","documentation":"This ArgumentError wraps the message thrown by assertMessageIdShape when the supplied messageId fails shape validation before bookmarking. Message IDs have a strict format the server expects; an invalid one would cause a pointless HTTP round trip, so the CLI rejects it locally, preserving the underlying message via e.message.","triggerScenarios":"Calling bookmark-add with messageId that is empty, whitespace, or otherwise violates assertMessageIdShape's expected format (e.g. passing a channel name, a UUID of another entity, or a truncated id).","commonSituations":"Copy-pasting a message reference from rendered output instead of the raw id, an off-by-one field selection in a script, or upstream tooling that changed its id format.","solutions":["Re-fetch the message (or list bookmarks/messages) and pass the exact messageId value from the API.","Trim whitespace and ensure you're not passing a display name or URL instead of the id.","Validate the format locally with the same rules as assertMessageIdShape before calling.","If ids come from another system, map them to Slock message ids first; cross-system ids are never valid."],"exampleFix":"// before\nawait bookmarkAdd(page, { messageId: row.title });\n// after\nawait bookmarkAdd(page, { messageId: row.messageId });","handlingStrategy":"validation","validationCode":"const messageId = String(kwargs.messageId ?? '').trim();\nif (!messageId) throw new Error('messageId required');","typeGuard":"const hasMessageIdShape = (v) => typeof v === 'string' && v.trim().length > 0 && !v.includes(' ');","tryCatchPattern":"try {\n  await bookmarkAdd(page, { messageId });\n} catch (e) {\n  if (e instanceof ArgumentError) {\n    console.error(`Invalid messageId \"${messageId}\": ${e.message}`);\n  } else throw e;\n}","preventionTips":["Pass messageId values straight from message-listing output, never display text.","Trim and sanity-check ids in scripts before calling.","Map foreign-system ids to Slock message ids first."],"tags":["validation","input-validation","argument-error","message-id"],"backgroundTag":"invalid-id-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}