{"record":{"id":"699b74aa7e63b350","repo":"jackwener/OpenCLI","slug":"e-message-699b74","errorCode":null,"errorMessage":"${e.message}","messagePattern":"\\$\\{e\\.message\\}","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/slock/bookmark-remove.js","lineNumber":26,"sourceCode":"\ncli({\n  site: SLOCK_SITE,\n  name: 'bookmark-remove',\n  access: 'write',\n  description: 'Remove a bookmark (DELETE /channels/saved/:messageId). 404 is treated as already-removed.',\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' },\n    { name: 'server', help: 'Override active server' },\n  ],\n  columns: ['messageId', 'removed', 'note'],\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/' + encodeURIComponent(${JSON.stringify(id)}), { method:'DELETE', credentials:'include', headers });\n      if (res.status === 404) return { kind: 'http', status: 404, where:'/channels/saved/:id' };\n      if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/channels/saved/:id' };\n      return { kind: 'ok', rows: [{ removed: true }] };\n    `;\n    const result = await page.evaluate(`(async () => { ${snippet} })()`);\n    if (result && result.kind === 'http' && result.status === 404) {\n      return [{ messageId: id, removed: true, note: 'idempotent (already absent)' }];\n    }\n    const rows = dispatchEvaluateResult(result);\n    return rows.map(() => ({ messageId: id, removed: true, note: '' }));\n  },\n});\n","sourceCodeStart":8,"sourceCodeEnd":43,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/slock/bookmark-remove.js#L8-L43","documentation":"This ArgumentError wraps the underlying message from assertMessageIdShape when the messageId argument to bookmark-remove fails shape validation. As with bookmark-add, the CLI validates locally before issuing the DELETE to /channels/saved/:id so bad ids never reach the server.","triggerScenarios":"Calling bookmark-remove with an empty, whitespace-only, or malformed messageId string — e.g. passing a bookmark row id instead of the message id, or a stale id pasted from output.","commonSituations":"Scripting bulk removals from a CSV where one column was misaligned, trimming errors that drop characters, or ids copied from a different server's export.","solutions":["Run bookmark-list to get current valid messageIds and use one of those values.","Check the argument for stray whitespace, quotes, or truncation before invoking.","Validate locally against the expected id shape (mirror assertMessageIdShape) to fail fast in scripts.","If automating, assert every id in the batch matches the format before starting the loop."],"exampleFix":"// before\nids.forEach(id => removeBookmark(page, { messageId: id }));\n// after\nids.filter(id => id && id.trim().length > 0).forEach(id => removeBookmark(page, { messageId: id.trim() }));","handlingStrategy":"validation","validationCode":"const id = String(messageId ?? '').trim();\nif (!id) throw new Error(`bookmark-remove: messageId must be non-empty, got \"${messageId}\"`);","typeGuard":"const hasMessageIdShape = (v) => typeof v === 'string' && v.trim().length > 0 && !v.includes(' ');","tryCatchPattern":"try {\n  await bookmarkRemove(page, { messageId });\n} catch (e) {\n  if (e instanceof ArgumentError) {\n    console.error(`Skipping invalid messageId \"${messageId}\": ${e.message}`);\n  } else throw e;\n}","preventionTips":["Validate each id in bulk scripts before starting removals.","Use bookmark-list output as the source of messageIds.","Trim/normalize ids when they pass through CSVs or shell variables."],"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"}