{"record":{"id":"3bf18a663e828c9a","repo":"bmad-code-org/BMAD-METHOD","slug":"resolvechannel-pinned-channel-requires-a-pin-valu","errorCode":null,"errorMessage":"resolveChannel: pinned channel requires a pin value","messagePattern":"resolveChannel: pinned channel requires a pin value","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/modules/channel-resolver.js","lineNumber":146,"sourceCode":" *\n * @param {Object} args\n * @param {'stable'|'next'|'pinned'} args.channel\n * @param {string} [args.pin] - Required when channel === 'pinned'\n * @param {string} args.repoUrl - Module's git URL (for tag lookup)\n * @returns {Promise<{channel, ref, version}>} where\n *   ref:     the git ref to pass to `git clone --branch`, or null for HEAD (next)\n *   version: the resolved version string (tag name for stable/pinned, 'main' for next)\n *\n * Throws on:\n *   - pinned without a pin value\n *   - stable with no GitHub repo parseable from the URL (pass through to caller to fall back)\n *\n * Falls back to next-channel semantics and sets resolvedFallback=true when\n * stable resolution turns up no tags.\n */\nasync function resolveChannel({ channel, pin, repoUrl, timeout }) {\n  if (channel === 'pinned') {\n    if (!pin) throw new Error('resolveChannel: pinned channel requires a pin value');\n    return { channel: 'pinned', ref: pin, version: pin, resolvedFallback: false };\n  }\n\n  if (channel === 'next') {\n    return { channel: 'next', ref: null, version: 'main', resolvedFallback: false };\n  }\n\n  if (channel === 'stable') {\n    const parsed = parseGitHubRepo(repoUrl);\n    if (!parsed) {\n      // No GitHub URL — caller must handle by falling back to next.\n      return { channel: 'next', ref: null, version: 'main', resolvedFallback: true, reason: 'not-a-github-url' };\n    }\n\n    try {\n      const tags = await fetchStableTags(parsed.owner, parsed.repo, { timeout });\n      if (tags.length === 0) {\n        return { channel: 'next', ref: null, version: 'main', resolvedFallback: true, reason: 'no-stable-tags' };","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/modules/channel-resolver.js#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait resolveChannel({ channel: 'pinned', repoUrl });\n\n// after\nawait resolveChannel({ channel: 'pinned', pin: 'v1.2.3', repoUrl });","handlingStrategy":"validation","validationCode":"if (channel === 'pinned' && !pin) {\n  throw new Error('The pinned channel requires --pin <tag>.');\n}","typeGuard":"function isValidChannelPlan({ channel, pin }) {\n  if (channel === 'pinned') return typeof pin === 'string' && pin.trim().length > 0;\n  return ['stable', 'next'].includes(channel);\n}","tryCatchPattern":"try {\n  await resolveChannel({ channel: 'pinned', pin, repoUrl });\n} catch (error) {\n  if (error.message === 'resolveChannel: pinned channel requires a pin value') { /* prompt for pin */ }\n  throw error;\n}","preventionTips":["Always pair channel='pinned' with a non-empty pin in channel plans.","Validate the plan with isValidChannelPlan before calling resolveChannel."],"tags":["channel-resolver","validation","modules"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}