jackwener/OpenCLI · error · ArgumentError

${e.message} (rethrown from classifyTarget; e.g. target requ

Error message

${e.message} (rethrown from classifyTarget; e.g. target required / dm target forms)

What it means

message-send.js resolves the --target via classifyTarget(target). If classifyTarget throws (e.g. its own 'target required' or unsupported DM target forms), the CLI catches it and rethrows it as an ArgumentError, preserving the original message. The appended parenthetical in the error index is illustrative of the rethrow pattern; the actual thrown message is classifyTarget's e.message.

Source

Thrown at clis/slock/message-send.js:39

    { name: 'dry-run', type: 'bool', default: false, help: 'Print the planned payload without sending' },
    { name: 'as-task', type: 'bool', default: false, help: 'Create the message as a task (asTask)' },
    { name: 'attach', help: 'Comma-separated attachmentId UUIDs (upload separately first)' },
    { name: 'server', help: 'Override active server (slug or id)' },
  ],
  columns: ['target', 'channelId', 'content', 'result', 'messageId'],
  func: async (page, kwargs) => {
    const target = String(kwargs.target ?? '').trim();
    if (!target) throw new ArgumentError('target required');
    const content = String(kwargs.content ?? '');
    const asTask = !!kwargs['as-task'];
    const attachmentIds = String(kwargs.attach ?? '')
      .split(',').map((s) => s.trim()).filter(Boolean);
    for (const aid of attachmentIds) {
      if (!UUID_RE.test(aid)) throw new ArgumentError(`--attach expects attachmentId UUIDs; "${aid}" is not a UUID`);
    }
    let cls;
    try { cls = classifyTarget(target); }
    catch (e) { throw new ArgumentError(e.message); }

    const extra = { asTask, attachmentIds };

    if (kwargs['dry-run']) {
      return [{
        target, channelId: '(not resolved in dry-run)', content,
        result: asTask ? 'dry-run (asTask)' : 'dry-run', messageId: null,
      }];
    }

    await page.goto(SLOCK_HOME_URL);
    const snippet = buildSendSnippet(target, content, cls, kwargs.server, extra);
    const result = await page.evaluate(`(async () => { ${snippet} })()`);
    const rows = dispatchEvaluateResult(result);
    const r = rows[0] ?? {};
    const messageId = r.id ?? r.messageId;
    if (!messageId) {
      throw new CommandExecutionError('Slock message-send succeeded without returning a message id; refusing to report a sent row.');

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Use a supported target form: `#channel-slug`, a channel UUID, or the DM form documented by classifyTarget.
  2. Read the original message in the error — it names exactly what classifyTarget rejected.
  3. Pre-validate the target (non-empty, starts with '#' or is a UUID, correct DM syntax) before invoking.
  4. Check the classifyTarget implementation for the accepted DM target forms.

Example fix

// before
--target @alice smith
// after
--target #general   (or --target 4c1e8b2a-... for a channel UUID, or the documented dm:<userId> form)
Defensive patterns

Strategy: validation

Validate before calling

const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
const t = String(kwargs.target ?? '').trim();
if (!t) throw new Error('target required');
if (!t.startsWith('#') && !UUID_RE.test(t) && !/^dm:/i.test(t)) throw new Error(`unsupported target form: ${t} (use #slug, channel UUID, or documented dm: form)`);

Type guard

const isValidTarget = (t) => typeof t === 'string' && !!t.trim() && (/^#/.test(t) || /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t) || /^dm:/i.test(t));

Try / catch

try { await sendMessage(page, kwargs); } catch (e) { if (e instanceof ArgumentError && /classifyTarget|target required|dm target/.test(e.message)) { console.error(`Bad --target: ${e.message}`); } else throw e; }

Prevention

When it happens

Trigger: Passing a target form classifyTarget rejects: empty/whitespace target, an unsupported DM target syntax (e.g. @user variants it can't parse), or otherwise malformed channel/DM identifiers.

Common situations: Using `@username#1234` or bare usernames where the classifier expects a specific DM form; passing a display name instead of a channel slug/UUID; leading '#' issues with unusual channel names.

Related errors


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