{"record":{"id":"fb502affb5534070","repo":"bmad-code-org/BMAD-METHOD","slug":"tag-planentry-pin-not-found-in-parsed-owner","errorCode":null,"errorMessage":"Tag '${planEntry.pin}' not found in ${parsed.owner}/${parsed.repo}.","messagePattern":"Tag '(.+?)' not found in (.+?)/(.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/modules/external-manager.js","lineNumber":346,"sourceCode":"      throw new Error(`Could not resolve stable tag for '${moduleCode}' (${error.message}). ${hint}`);\n    }\n\n    if (resolved.resolvedFallback && !silent) {\n      if (resolved.reason === 'no-stable-tags') {\n        await prompts.log.warn(`No stable releases found for ${moduleInfo.name}; installing from main.`);\n      } else if (resolved.reason === 'not-a-github-url') {\n        await prompts.log.warn(`Cannot determine stable tags for ${moduleInfo.name} (non-GitHub URL); installing from main.`);\n      }\n    }\n\n    // Validate pin before we burn time cloning. Best-effort: skip on non-GitHub URLs.\n    if (planEntry.channel === 'pinned') {\n      const parsed = parseGitHubRepo(moduleInfo.url);\n      if (parsed) {\n        try {\n          const exists = await tagExists(parsed.owner, parsed.repo, planEntry.pin);\n          if (!exists) {\n            throw new Error(`Tag '${planEntry.pin}' not found in ${parsed.owner}/${parsed.repo}.`);\n          }\n        } catch (error) {\n          if (error.message?.includes('not found')) throw error;\n          // Network hiccup on tag verification — let the clone attempt fail clearly.\n        }\n      }\n    }\n\n    // ─── Clone or update cache by resolved channel ────────────────────────\n    const markerPath = path.join(moduleCacheDir, '.bmad-channel.json');\n    const currentMarker = await readChannelMarker(markerPath);\n    const needsChannelReset = currentMarker && currentMarker.channel !== resolved.channel;\n\n    let needsDependencyInstall = false;\n    let wasNewClone = false;\n\n    if (needsChannelReset && (await fs.pathExists(moduleCacheDir))) {\n      // Channel changed (e.g. user switched stable→next). Blow away and re-clone","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/modules/external-manager.js#L328-L364","documentation":"Thrown by cloneExternalModule() during pinned-channel validation when tagExists() confirms the requested --pin tag does not exist in the module's GitHub repository (owner/repo). The check runs before cloning to fail fast and avoid wasting time on a clone that would fail anyway.","triggerScenarios":"Installing with --pin <moduleCode>=<tag> where <tag> does not exist in the module's GitHub repo. The tagExists() call queries the GitHub API and returns false. Note: this check only runs when the module URL is a GitHub URL (parseGitHubRepo succeeds).","commonSituations":"Typo in the tag name; the tag was deleted or never created; the user confused a branch name with a tag name; the version number format is wrong (v1.0 vs 1.0.0).","solutions":["List available tags: visit the GitHub releases page or run 'git ls-remote --tags <repo-url>'.","Correct the tag name in the --pin flag.","If the tag exists but under a different format, match the exact string (e.g., 'v1.2.3' vs '1.2.3').","If you want the latest main branch instead, use --next=<moduleCode> instead of --pin."],"exampleFix":"# before\nnpx bmad-method install --pin my-module=v2.0.0\n# (tag 'v2.0.0' doesn't exist)\n\n# after\n# Check tags: git ls-remote --tags https://github.com/org/repo.git\nnpx bmad-method install --pin my-module=2.0.0","handlingStrategy":"validation","validationCode":"const { tagExists, parseGitHubRepo } = require('./channel-resolver');\n\n// Pre-validate the pin tag exists\nconst moduleInfo = await extMgr.getModuleByCode(moduleCode);\nconst parsed = parseGitHubRepo(moduleInfo.url);\nif (parsed) {\n  const exists = await tagExists(parsed.owner, parsed.repo, requestedTag);\n  if (!exists) {\n    throw new Error(`Tag '${requestedTag}' not found in ${parsed.owner}/${parsed.repo}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await extMgr.cloneExternalModule(moduleCode, { channelOptions: { pins: new Map([[moduleCode, tag]]) } });\n} catch (e) {\n  if (e.message.includes('not found in')) {\n    console.error('The pinned tag does not exist. List tags with: git ls-remote --tags <repo-url>');\n    // Fall back to --next\n    await extMgr.cloneExternalModule(moduleCode, { channelOptions: { nextSet: new Set([moduleCode]) } });\n    return;\n  }\n  throw e;\n}","preventionTips":["List available tags with 'git ls-remote --tags' or the GitHub releases page before pinning.","Match the exact tag format used by the repository (v-prefixed vs unprefixed).","Use --next as a fallback when a specific tag doesn't exist."],"tags":["git","tag-validation","external-modules","github-api","pinning"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}