jackwener/OpenCLI · error · ArgumentError
${e.message}
Error message
${e.message} What it means
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.
Source
Thrown at clis/slock/bookmark-remove.js:26
cli({
site: SLOCK_SITE,
name: 'bookmark-remove',
access: 'write',
description: 'Remove a bookmark (DELETE /channels/saved/:messageId). 404 is treated as already-removed.',
domain: SLOCK_DOMAIN,
strategy: Strategy.COOKIE,
browser: true,
siteSession: 'persistent',
args: [
{ name: 'messageId', positional: true, required: true, help: 'Full messageId UUID' },
{ name: 'server', help: 'Override active server' },
],
columns: ['messageId', 'removed', 'note'],
func: async (page, kwargs) => {
let id;
try { id = assertMessageIdShape(String(kwargs.messageId ?? '')); }
catch (e) { throw new ArgumentError(e.message); }
await page.goto(SLOCK_HOME_URL);
const snippet = `
${authHeadersFragment({ serverScoped: true, serverIdOverride: kwargs.server })}
const res = await fetch('${SLOCK_API_BASE}/channels/saved/' + encodeURIComponent(${JSON.stringify(id)}), { method:'DELETE', credentials:'include', headers });
if (res.status === 404) return { kind: 'http', status: 404, where:'/channels/saved/:id' };
if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/channels/saved/:id' };
return { kind: 'ok', rows: [{ removed: true }] };
`;
const result = await page.evaluate(`(async () => { ${snippet} })()`);
if (result && result.kind === 'http' && result.status === 404) {
return [{ messageId: id, removed: true, note: 'idempotent (already absent)' }];
}
const rows = dispatchEvaluateResult(result);
return rows.map(() => ({ messageId: id, removed: true, note: '' }));
},
});
View on GitHub (pinned to 49907e53dc)
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.
Example fix
// before
ids.forEach(id => removeBookmark(page, { messageId: id }));
// after
ids.filter(id => id && id.trim().length > 0).forEach(id => removeBookmark(page, { messageId: id.trim() })); Defensive patterns
Strategy: validation
Validate before calling
const id = String(messageId ?? '').trim();
if (!id) throw new Error(`bookmark-remove: messageId must be non-empty, got "${messageId}"`); Type guard
const hasMessageIdShape = (v) => typeof v === 'string' && v.trim().length > 0 && !v.includes(' '); Try / catch
try {
await bookmarkRemove(page, { messageId });
} catch (e) {
if (e instanceof ArgumentError) {
console.error(`Skipping invalid messageId "${messageId}": ${e.message}`);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ${e.message}
- series_id must be a non-empty value
- Invalid Chess.com username "${value}" Usernames are 3-25 cha
- coingecko derivatives limit must be a positive integer
- limit must be a positive integer
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/699b74aa7e63b350.
Report an issue: GitHub.