jackwener/OpenCLI · error · ArgumentError

${e.message} (rethrown as ArgumentError)

Error message

${e.message} (rethrown as ArgumentError)

What it means

The thread-follow command validates the parentMessageId with assertMessageIdShape and rethrows failures as an ArgumentError with a "(rethrown as ArgumentError)" suffix. This separates input-shape errors from network/API errors so callers can react to bad input deterministically.

Source

Thrown at clis/slock/thread-follow.js:29

// thread-unfollow/-done/-undone commands.
cli({
  site: SLOCK_SITE,
  name: 'thread-follow',
  access: 'write',
  description: 'Follow the thread on a parent message (POST /channels/threads/follow)',
  domain: SLOCK_DOMAIN,
  strategy: Strategy.COOKIE,
  browser: true,
  siteSession: 'persistent',
  args: [
    { name: 'parentMessageId', positional: true, required: true, help: 'Full parent messageId UUID (short ids rejected)' },
    { name: 'server', help: 'Override active server' },
  ],
  columns: ['parentMessageId', 'threadChannelId', 'result'],
  func: async (page, kwargs) => {
    let id;
    try { id = assertMessageIdShape(String(kwargs.parentMessageId ?? '')); }
    catch (e) { throw new ArgumentError(e.message); }
    await page.goto(SLOCK_HOME_URL);
    const snippet = buildFetchSnippet({
      method: 'POST',
      path: '/channels/threads/follow',
      body: { parentMessageId: id },
      serverScoped: true,
      serverIdOverride: kwargs.server,
    });
    const result = await page.evaluate(`(async () => { ${snippet} })()`);
    const data = dispatchEvaluateResult(result);
    const threadChannelId = data?.threadChannelId ?? data?.channelId ?? data?.id;
    if (!threadChannelId) {
      throw new CommandExecutionError(`Slock thread-follow succeeded without returning a thread channel id for parent message ${id}.`);
    }
    return [{ parentMessageId: id, threadChannelId, result: 'followed' }];
  },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Take parentMessageId from the message-read/list output, not from a thread or channel id.
  2. Echo the id before invoking and validate it matches the expected id shape.
  3. Trim whitespace and strip stray quotes before passing.
  4. Wrap the call in a try/catch for ArgumentError and print corrected usage.

Example fix

// before
await cli.run(['thread-follow', '--parent-message-id', threadChannelId]); // wrong id kind
// after
await cli.run(['thread-follow', '--parent-message-id', message.parentMessageId]);
Defensive patterns

Strategy: validation

Validate before calling

const id = String(kwargs.parentMessageId ?? '').trim();
if (!id) throw new Error('parentMessageId is required');

Type guard

function looksLikeMessageId(s) { return typeof s === 'string' && /^[A-Za-z0-9_-]{6,}$/.test(s.trim()); }

Try / catch

try {
  await cli.run(['thread-follow', '--parent-message-id', id]);
} catch (e) {
  if (String(e.message).includes('rethrown as ArgumentError')) {
    console.error(`"${id}" is not a valid parent message id — fetch one via message-read`);
  } else throw e;
}

Prevention

When it happens

Trigger: Running `slock thread-follow` with a parentMessageId that is empty, malformed, or not the id format assertMessageIdShape expects (e.g. a channel id or thread id passed instead of the parent message id).

Common situations: Passing a threadChannelId where a parent message id is required; unset variables in shell scripts; ids mangled by quoting/interpolation in wrappers.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/0f71f62902957f60. Report an issue: GitHub.