{"record":{"id":"67b169e0c4ea7763","repo":"bmad-code-org/BMAD-METHOD","slug":"failed-to-clone-external-module-modulecode-at","errorCode":null,"errorMessage":"Failed to clone external module '${moduleCode}' at ${resolved.version}: ${error.message}","messagePattern":"Failed to clone external module '(.+?)' at (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/modules/external-manager.js","lineNumber":431,"sourceCode":"    if (wasNewClone) {\n      const fetchSpinner = await createSpinner();\n      fetchSpinner.start(`Fetching ${moduleInfo.name}...`);\n      try {\n        if (resolved.channel === 'next') {\n          execSync(`git clone --depth 1 \"${moduleInfo.url}\" \"${moduleCacheDir}\"`, {\n            stdio: ['ignore', 'pipe', 'pipe'],\n            env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),\n          });\n        } else {\n          execSync(`git clone --depth 1 --branch ${quoteShell(resolved.ref)} \"${moduleInfo.url}\" \"${moduleCacheDir}\"`, {\n            stdio: ['ignore', 'pipe', 'pipe'],\n            env: gitEnv({ GIT_TERMINAL_PROMPT: '0' }),\n          });\n        }\n        fetchSpinner.stop(`Fetched ${moduleInfo.name}`);\n      } catch (error) {\n        fetchSpinner.error(`Failed to fetch ${moduleInfo.name}`);\n        throw new Error(`Failed to clone external module '${moduleCode}' at ${resolved.version}: ${error.message}`);\n      }\n    }\n\n    // Record resolution (channel + tag + SHA) for the manifest writer to pick up.\n    const sha = execSync('git rev-parse HEAD', { cwd: moduleCacheDir, stdio: 'pipe', env: gitEnv() }).toString().trim();\n    ExternalModuleManager._resolutions.set(moduleCode, {\n      channel: resolved.channel,\n      version: resolved.version,\n      ref: resolved.ref,\n      sha,\n      repoUrl: moduleInfo.url,\n      resolvedFallback: !!resolved.resolvedFallback,\n      planSource: planEntry.source,\n    });\n    await writeChannelMarker(markerPath, { channel: resolved.channel, version: resolved.version, sha });\n\n    // Install dependencies if package.json exists\n    const packageJsonPath = path.join(moduleCacheDir, 'package.json');","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/modules/external-manager.js#L413-L449","documentation":"Thrown by cloneExternalModule() inside the git clone catch block when execSync('git clone ...') fails for an external module during a fresh clone (wasNewClone path). The error includes the module code, resolved version, and the underlying git error message.","triggerScenarios":"The module's repository URL is unreachable or doesn't exist; the resolved ref (tag or branch) doesn't exist at clone time despite passing earlier validation; network failure; authentication required; the git binary is missing. This fires only when no cache existed and the initial clone fails.","commonSituations":"Repository was deleted or made private after being added to the registry; transient network outage; SSH key issues for git@ URLs; corporate proxy blocks the clone; the resolved tag was deleted between tagExists() and clone.","solutions":["Verify the repository URL is accessible: try 'git clone <url>' manually.","Check network connectivity and proxy/firewall settings.","If the repo is private, ensure credentials are configured.","Retry — transient network failures are common.","If the tag was deleted upstream, switch to --next or a different --pin value."],"exampleFix":"# before — repo moved or tag deleted\nnpx bmad-method install --pin my-module=deleted-tag\n\n# after\n# Verify manually: git clone https://github.com/org/repo.git\nnpx bmad-method install --next=my-module","handlingStrategy":"retry","validationCode":"// Pre-flight: verify repo is reachable\nconst { execSync } = require('child_process');\n\nfunction isRepoReachable(url) {\n  try {\n    execSync(`git ls-remote --exit-code \"${url}\" HEAD`, { stdio: 'ignore', timeout: 15000 });\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nconst moduleInfo = await extMgr.getModuleByCode(moduleCode);\nif (!isRepoReachable(moduleInfo.url)) {\n  throw new Error(`Repository ${moduleInfo.url} is not reachable`);\n}","typeGuard":null,"tryCatchPattern":"for (let attempt = 1; attempt <= 3; attempt++) {\n  try {\n    await extMgr.cloneExternalModule(moduleCode, options);\n    break;\n  } catch (e) {\n    if (e.message.startsWith('Failed to clone external module') && attempt < 3) {\n      await new Promise(r => setTimeout(r, 2000 * attempt));\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["Verify the module's repository URL is accessible before installing.","Configure credentials for private repositories.","Retry on transient network failures.","Use --next or a different --pin if the ref was deleted upstream."],"tags":["network","git","clone","external-modules","authentication"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}