jackwener/OpenCLI · error · ArgumentError

Discord channel navigation requires both guild_id and channe

Error message

Discord channel navigation requires both guild_id and channel_id.

What it means

buildDiscordChannelUrl constructs the discord.com/channels/<guild>/<channel>[/<thread>] URL and throws ArgumentError when guildId or channelId is missing. Discord channel URLs require both identifiers, so any target resolution that ends up without both (via parseDiscordChannelUrl, resolveDiscordChannelTarget or resolveDiscordThreadTarget) fails fast with this error.

Source

Thrown at clis/discord-app/utils.js:94

    const parts = url.pathname.split('/').filter(Boolean);
    if (parts[0] !== 'channels' || parts.length < 3) return null;

    const guildId = decodeURIComponent(parts[1] || '');
    const channelId = decodeURIComponent(parts[2] || '');
    const threadId = parts[3] ? decodeURIComponent(parts[3]) : undefined;
    if (!guildId || !channelId) return null;

    return {
        guild_id: guildId,
        channel_id: channelId,
        ...(threadId ? { thread_id: threadId } : {}),
        url: buildDiscordChannelUrl({ guildId, channelId, threadId }),
    };
}

export function buildDiscordChannelUrl({ guildId, channelId, threadId }) {
    if (!guildId || !channelId) {
        throw new ArgumentError('Discord channel navigation requires both guild_id and channel_id.');
    }
    const base = `${DISCORD_ORIGIN}/channels/${encodeURIComponent(String(guildId))}/${encodeURIComponent(String(channelId))}`;
    return threadId ? `${base}/${encodeURIComponent(String(threadId))}` : base;
}

export function parsePositiveInt(value, fallback, label) {
    if (value === undefined || value === null || value === '') return fallback;
    const raw = String(value).trim();
    if (!/^\d+$/.test(raw)) {
        throw new ArgumentError(`--${label} must be a positive integer.`);
    }
    const parsed = parseInt(raw, 10);
    if (!Number.isFinite(parsed) || parsed <= 0) {
        throw new ArgumentError(`--${label} must be a positive integer.`);
    }
    return parsed;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Provide a full Discord channel URL of the form https://discord.com/channels/<guild_id>/<channel_id>
  2. When using id-based targeting, pass both --guild and --channel
  3. Use server/channel names instead of raw ids so resolveDiscordChannelTarget can resolve the missing id from the live app
  4. Verify the URL parse output (parseDiscordChannelUrl) contains both snowflakes before calling navigation

Example fix

// before
await discordAppRead(page, { channel: '123456789012345678' });
// after
await discordAppRead(page, { guild: '987654321098765432', channel: '123456789012345678' });
Defensive patterns

Strategy: validation

Validate before calling

function validateChannelTarget({ url, guild, channel }) {
  if (url) {
    const parts = url.replace(/\/$/, '').split('/');
    if (!/^discord\.com$/.test(new URL(url).hostname) || parts.length < 5) {
      throw new Error('URL must be https://discord.com/channels/<guild_id>/<channel_id>');
    }
  } else if (!guild || !channel) {
    throw new Error('Provide both --guild and --channel, or a full channel URL.');
  }
}

Type guard

function isSnowflake(v) {
  return typeof v === 'string' && /^\d{15,21}$/.test(v);
}
function hasCompleteTarget(t) {
  return isSnowflake(t?.guildId) && isSnowflake(t?.channelId);
}

Try / catch

try {
  await discordAppRead(page, { url: channelUrl });
} catch (err) {
  if (String(err.message).includes('requires both guild_id and channel_id')) {
    console.error('Incomplete target: use /channels/<guild>/<channel> URL or pass --guild and --channel together.');
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a --url that is not a valid Discord channel URL (missing guild or channel segment); supplying --channel without --guild and no resolvable server context; resolveDiscordThreadTarget building a URL from a thread id without a channel id; programmatic calls to buildDiscordChannelUrl with undefined guildId/channelId.

Common situations: Passing a discord.com/invite or discord.com/channels/<guild> partial URL; a malformed custom URL missing path segments; forgetting that name-based targeting requires the channel to be found in the current server before a URL can be built; snowflake typos where one id is 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/99feafbdac236e66. Report an issue: GitHub.