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
- Provide a full Discord channel URL of the form https://discord.com/channels/<guild_id>/<channel_id>
- When using id-based targeting, pass both --guild and --channel
- Use server/channel names instead of raw ids so resolveDiscordChannelTarget can resolve the missing id from the live app
- 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
- Always pass full /channels/<guild>/<channel> URLs
- Pair --guild with --channel when using ids
- Prefer name-based targeting so the resolver fills missing ids
- Validate snowflakes (15-21 digits) before invoking the CLI
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
- --url must be a Discord channel URL like https://discord.com
- Pass --url or --guild/--channel to choose a Discord channel.
- Pass --channel with --guild, or use --url.
- --url must be a Discord thread/post URL like https://discord
- Pass --thread <thread_id> or --url <thread_url>.
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/99feafbdac236e66.
Report an issue: GitHub.