jackwener/OpenCLI · error · ArgumentError

messageId required

Error message

messageId required

What it means

task-convert requires a positional messageId; the func trims the argument and throws ArgumentError when it is empty. Accepted forms are a full message UUID or a '#channel:shortId' reference expanded via /messages/context.

Source

Thrown at clis/slock/task-convert.js:40

import { UUID_RE, classifyThreadTarget } from './resolve.js';

cli({
  site: SLOCK_SITE,
  name: 'task-convert',
  access: 'write',
  description: 'Convert a message into a chat task (POST /tasks/convert-message). Accepts a message UUID or "#channel:shortId".',
  domain: SLOCK_DOMAIN,
  strategy: Strategy.COOKIE,
  browser: true,
  siteSession: 'persistent',
  args: [
    { name: 'messageId', positional: true, required: true, help: 'Full message UUID, or "#channel:shortId" (short id expanded via /messages/context)' },
    { name: 'server', help: 'Override active server' },
  ],
  columns: ['id', 'taskNumber', 'title', 'taskStatus', 'channelId'],
  func: async (page, kwargs) => {
    const raw = String(kwargs.messageId ?? '').trim();
    if (!raw) throw new ArgumentError('messageId required');

    // Decide shape: bare UUID, or "#channel:shortId".
    let resolveFragment;
    if (UUID_RE.test(raw)) {
      resolveFragment = `const fullMsgId = ${JSON.stringify(raw)};`;
    } else {
      const tt = classifyThreadTarget(raw);
      if (!tt) {
        throw new ArgumentError(`messageId "${raw}" is not a UUID or a "#channel:shortId" form`);
      }
      const isUuid = UUID_RE.test(tt.parentTarget);
      const parent = JSON.stringify(tt.parentTarget.replace(/^#/, '').toLowerCase());
      const pmsg = JSON.stringify(tt.parentMsgId);
      // Phase 7.1 invariant baked in: we read cxd.targetMessageId, NOT
      // m.message.id. The latter is the closest-message-in-context object,
      // which can be a neighbor when the short id is just a prefix.
      resolveFragment = `
        let parentChannelId;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Provide the message UUID or '#channel:shortId' as the positional argument.
  2. Verify the variable feeding the argument is non-empty before invoking.
  3. Check command usage/help to confirm the positional argument name and accepted forms.

Example fix

// before
slock task-convert "$MSG_ID"   # MSG_ID is empty
// after
: "${MSG_ID:?MSG_ID must be set}" && slock task-convert "$MSG_ID"
Defensive patterns

Strategy: validation

Validate before calling

const raw = String(messageId ?? '').trim();
if (!raw) throw new Error('messageId is required (UUID or #channel:shortId)');

Type guard

const hasMessageId = (v) => typeof v === 'string' && v.trim().length > 0;

Try / catch

try {
  await cli('task-convert', msgId);
} catch (e) {
  if (e instanceof ArgumentError && e.message === 'messageId required') {
    console.error('Usage: task-convert <messageUUID | #channel:shortId>');
    process.exitCode = 2;
  } else throw e;
}

Prevention

When it happens

Trigger: Running task-convert with no positional argument, or with a value that is whitespace only after trimming.

Common situations: Piping an empty variable into the command; forgetting the argument when converting a message to a task; a shell expansion that produced an empty string.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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