jackwener/OpenCLI · error · CommandExecutionError
${context} returned messages from the wrong Discord target.
Error message
${context} returned messages from the wrong Discord target. Expected channel/thread id ${expectedChannelId}, saw ${actualChannelId}. What it means
This is the final cross-check in assertDiscordMessageRowsBelongToTarget: a row's channel_id must equal the expected target thread_id/channel_id. A mismatch proves the rendered message list belongs to a different channel than requested, so the results are rejected with CommandExecutionError.
Source
Thrown at clis/discord-app/utils.js:610
export function assertDiscordMessageRowsBelongToTarget(rows, target, context = 'Discord read') {
if (!target) return rows;
const expectedChannelId = String(target.thread_id || target.channel_id || '');
if (!expectedChannelId) {
throw new CommandExecutionError(`${context} target is missing a stable channel/thread id.`);
}
for (const row of rows) {
if (!row || typeof row !== 'object' || Array.isArray(row)) {
throw new CommandExecutionError(`${context} returned malformed message rows.`);
}
const actualChannelId = row.channel_id == null || row.channel_id === '' ? '' : String(row.channel_id);
if (!actualChannelId) {
throw new CommandExecutionError(
`${context} could not verify returned message target.`,
`Expected channel/thread id ${expectedChannelId}, but the message row did not include channel_id.`,
);
}
if (actualChannelId && actualChannelId !== expectedChannelId) {
throw new CommandExecutionError(
`${context} returned messages from the wrong Discord target.`,
`Expected channel/thread id ${expectedChannelId}, saw ${actualChannelId}.`,
);
}
}
return rows;
}
export async function resolveDiscordThreadTarget(page, kwargs = {}) {
const urlArg = stringArg(kwargs.url);
if (urlArg) {
const parsed = parseDiscordChannelUrl(urlArg);
if (!parsed || !parsed.thread_id) {
throw new ArgumentError('--url must be a Discord thread/post URL like https://discord.com/channels/<guild_id>/<channel_id>/<thread_id>.');
}
return parsed;
}
View on GitHub (pinned to 49907e53dc)
Solutions
- Wait for the route to settle before reading: call waitForDiscordRoute and/or waitForDiscordContent before harvesting messages.
- Verify the resolved target ids match what you intended ("opencli discord-app channels -f json").
- Re-run the command — transient navigation races usually resolve on retry.
- Navigate explicitly via --url with the full channel URL instead of name-based resolution.
Example fix
// before
await resolveDiscordChannelTarget(page, kwargs);
const rows = await scrapeMessages(page); // raced navigation
// after
const target = await resolveDiscordChannelTarget(page, kwargs, { required: true });
await waitForDiscordRoute(page, target);
await waitForDiscordContent(page, 'messages');
const rows = assertDiscordMessageRowsBelongToTarget(await scrapeMessages(page), target); Defensive patterns
Strategy: retry
Validate before calling
const expected = String(target.thread_id || target.channel_id || '');
if (rows.some(r => r && String(r.channel_id ?? '') !== expected)) throw new Error('Rows channel mismatch before verification'); Type guard
null
Try / catch
try { rows = assertDiscordMessageRowsBelongToTarget(rows, target, ctx); } catch (e) { if (String(e.message).includes('wrong Discord target')) { await waitForDiscordRoute(page, target); await waitForDiscordContent(page, 'messages'); rows = assertDiscordMessageRowsBelongToTarget(await scrapeMessages(page), target, ctx); } else throw e; } Prevention
- Always waitForDiscordRoute (and content) between resolving a target and reading messages.
- Use full --url deep links to avoid redirect-to-default-channel behavior.
- Discard DOM caches between channel switches; re-harvest after navigation.
- Retry once on mismatch — it is usually a navigation race.
When it happens
Trigger: Discord actually rendered a different channel than the one resolved (stale navigation, redirected route, pinned/last-active channel) and the scraper harvested rows whose channel_id differs from expectedChannelId.
Common situations: Race between navigation and message harvesting; the app redirected to a default channel after a failed deep link; clicking behavior landing on a nearby channel; cached DOM from the previously opened channel.
Related errors
- ${context} target is missing a stable channel/thread id.
- ${context} returned malformed message rows.
- ${context} could not verify returned message target. Expecte
- Ctrip hotel-search returned malformed SSR hotel list
- discord-app channels
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/2371ef8a828b9d1a.
Report an issue: GitHub.