bmad-code-org/BMAD-METHOD · error · Error
resolveChannel: unknown channel '${channel}'
Error message
resolveChannel: unknown channel '${channel}' What it means
Thrown by resolveChannel when the channel argument is none of 'stable', 'next', or 'pinned'. This is a programmer/contract error: the channel resolver only knows those three strategies.
Source
Thrown at tools/installer/modules/channel-resolver.js:175
// No GitHub URL — caller must handle by falling back to next.
return { channel: 'next', ref: null, version: 'main', resolvedFallback: true, reason: 'not-a-github-url' };
}
try {
const tags = await fetchStableTags(parsed.owner, parsed.repo, { timeout });
if (tags.length === 0) {
return { channel: 'next', ref: null, version: 'main', resolvedFallback: true, reason: 'no-stable-tags' };
}
const top = tags[0];
return { channel: 'stable', ref: top.tag, version: top.tag, resolvedFallback: false };
} catch (error) {
// Propagate the error; callers decide whether to fall back or abort.
error.message = `Failed to resolve stable channel for ${parsed.owner}/${parsed.repo}: ${error.message}`;
throw error;
}
}
throw new Error(`resolveChannel: unknown channel '${channel}'`);
}
/**
* Verify that a specific tag exists in a GitHub repo. Used to validate
* --pin values before the user sits through a long clone that then fails.
*/
async function tagExists(owner, repo, tagName, { timeout } = {}) {
const url = `${GITHUB_API_BASE}/repos/${owner}/${repo}/git/refs/tags/${encodeURIComponent(tagName)}`;
try {
await fetchJson(url, { timeout });
return true;
} catch (error) {
if (error.statusCode === 404) return false;
throw error;
}
}
/**View on GitHub (pinned to b70486b9bd)
Solutions
- Use one of the supported channels: 'stable', 'next', or 'pinned'.
- Inspect the channel-plan/channel-resolver output to find where the bad channel string originates.
- If migrating from an older vocabulary, normalize legacy channel names before calling resolveChannel.
Example fix
// before
await resolveChannel({ channel: 'latest', repoUrl });
// after
await resolveChannel({ channel: 'stable', repoUrl }); Defensive patterns
Strategy: type-guard
Validate before calling
const SUPPORTED = new Set(['stable', 'next', 'pinned']);
if (!SUPPORTED.has(channel)) {
throw new Error(`Unsupported channel '${channel}'. Use stable, next, or pinned.`);
} Type guard
function isSupportedChannel(channel) {
return channel === 'stable' || channel === 'next' || channel === 'pinned';
} Try / catch
try {
await resolveChannel({ channel, repoUrl });
} catch (error) {
if (error.message.startsWith("resolveChannel: unknown channel '")) { /* normalize channel */ }
throw error;
} Prevention
- Restrict channel values to the supported set when building channel plans.
- Add a normalization/migration step for any legacy channel vocabulary before resolving.
When it happens
Trigger: resolveChannel({ channel: <something else>, ... }) — e.g. channel='latest', undefined, null, or a typo like 'stab le'.
Common situations: A module config or channel-plan builder emitted an unsupported channel string, a typo in CLI input, or an unhandled migration from an old channel vocabulary.
Related errors
- resolveChannel: pinned channel requires a pin value
- Unexpected response from ${url}
- Async validation is not supported by @clack/prompts. Please
- Obsolete implementation terminology found in deployable docu
- llms.txt must describe Build as canonical for both direct in
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/08207992a1aa7f4f.
Report an issue: GitHub.