bmad-code-org/BMAD-METHOD · error · Error
resolveChannel: pinned channel requires a pin value
Error message
resolveChannel: pinned channel requires a pin value
What it means
Thrown by resolveChannel when channel === 'pinned' but no pin value was supplied. The pinned channel requires an explicit tag/ref to clone; without one the resolver cannot pick a ref.
Source
Thrown at tools/installer/modules/channel-resolver.js:146
*
* @param {Object} args
* @param {'stable'|'next'|'pinned'} args.channel
* @param {string} [args.pin] - Required when channel === 'pinned'
* @param {string} args.repoUrl - Module's git URL (for tag lookup)
* @returns {Promise<{channel, ref, version}>} where
* ref: the git ref to pass to `git clone --branch`, or null for HEAD (next)
* version: the resolved version string (tag name for stable/pinned, 'main' for next)
*
* Throws on:
* - pinned without a pin value
* - stable with no GitHub repo parseable from the URL (pass through to caller to fall back)
*
* Falls back to next-channel semantics and sets resolvedFallback=true when
* stable resolution turns up no tags.
*/
async function resolveChannel({ channel, pin, repoUrl, timeout }) {
if (channel === 'pinned') {
if (!pin) throw new Error('resolveChannel: pinned channel requires a pin value');
return { channel: 'pinned', ref: pin, version: pin, resolvedFallback: false };
}
if (channel === 'next') {
return { channel: 'next', ref: null, version: 'main', resolvedFallback: false };
}
if (channel === 'stable') {
const parsed = parseGitHubRepo(repoUrl);
if (!parsed) {
// 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' };View on GitHub (pinned to b70486b9bd)
Solutions
- Provide a pin tag: pass `--pin v1.2.3` (or set pin in the channel plan).
- Switch to the 'stable' or 'next' channel if you do not need a specific tag.
- Validate the pin is non-empty before calling resolveChannel.
Example fix
// before
await resolveChannel({ channel: 'pinned', repoUrl });
// after
await resolveChannel({ channel: 'pinned', pin: 'v1.2.3', repoUrl }); Defensive patterns
Strategy: validation
Validate before calling
if (channel === 'pinned' && !pin) {
throw new Error('The pinned channel requires --pin <tag>.');
} Type guard
function isValidChannelPlan({ channel, pin }) {
if (channel === 'pinned') return typeof pin === 'string' && pin.trim().length > 0;
return ['stable', 'next'].includes(channel);
} Try / catch
try {
await resolveChannel({ channel: 'pinned', pin, repoUrl });
} catch (error) {
if (error.message === 'resolveChannel: pinned channel requires a pin value') { /* prompt for pin */ }
throw error;
} Prevention
- Always pair channel='pinned' with a non-empty pin in channel plans.
- Validate the plan with isValidChannelPlan before calling resolveChannel.
When it happens
Trigger: resolveChannel({ channel: 'pinned', pin: undefined|null|'' , repoUrl }) — a caller (e.g. external-manager.js or ui.js) constructed a pinned channel plan without a pin.
Common situations: A module config/CLI flag selects the pinned channel but the user did not pass `--pin <tag>`, or a programmatic caller forgot to set the pin field.
Related errors
- resolveChannel: unknown channel '${channel}'
- 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/3bf18a663e828c9a.
Report an issue: GitHub.