{"record":{"id":"5272c575933145d5","repo":"bmad-code-org/BMAD-METHOD","slug":"subdirectory-parsed-subdir-not-found-in-clone","errorCode":null,"errorMessage":"Subdirectory '${parsed.subdir}' not found in cloned repository","messagePattern":"Subdirectory '(.+?)' not found in cloned repository","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"tools/installer/modules/custom-module-manager.js","lineNumber":347,"sourceCode":"  async resolveSource(input, options = {}) {\n    const parsed = this.parseSource(input);\n    if (!parsed.isValid) throw new Error(parsed.error);\n\n    let rootDir;\n    let repoPath;\n    let sourceUrl;\n\n    if (parsed.type === 'local') {\n      rootDir = parsed.localPath;\n      repoPath = null;\n      sourceUrl = null;\n    } else {\n      repoPath = await this.cloneRepo(input, options);\n      sourceUrl = parsed.cloneUrl;\n      rootDir = parsed.subdir ? path.join(repoPath, parsed.subdir) : repoPath;\n\n      if (parsed.subdir && !(await fs.pathExists(rootDir))) {\n        throw new Error(`Subdirectory '${parsed.subdir}' not found in cloned repository`);\n      }\n    }\n\n    const marketplace = await this.readMarketplaceJsonFromDisk(rootDir);\n    const mode = marketplace ? 'discovery' : 'direct';\n\n    return { parsed, rootDir, repoPath, sourceUrl, marketplace, mode };\n  }\n\n  // ─── Clone ────────────────────────────────────────────────────────────────\n\n  /**\n   * Get the cache directory for custom modules.\n   * @returns {string} Path to the custom modules cache directory\n   */\n  getCacheDir() {\n    return path.join(os.homedir(), '.bmad', 'cache', 'custom-modules');\n  }","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/tools/installer/modules/custom-module-manager.js#L329-L365","documentation":"Thrown by resolveSource() after a successful clone when the URL contained a subdirectory reference (via /tree/<ref>/<subdir> or ?path=/subdir) but that subdirectory does not exist inside the cloned repository. The check uses fs.pathExists on path.join(repoPath, subdir).","triggerScenarios":"Cloning a URL like https://github.com/org/repo/tree/main/src/old-folder where 'src/old-folder' was deleted or renamed after the referenced ref. Also when a deep-path URL points at a path that only exists on a different branch.","commonSituations":"The repository was restructured and the subdirectory moved or removed; the user copied a deep-link URL from a different branch; the /tree/ path segment was misinterpreted during parsing.","solutions":["Open the repository in a browser at the cloned ref and verify the subdirectory path exists.","Remove the subdirectory from the URL to clone the whole repo, then navigate to the correct path.","Pin to a version/tag where the subdirectory is known to exist."],"exampleFix":"// before\nawait mgr.resolveSource('https://github.com/org/repo/tree/main/src/old-folder');\n\n// after\nawait mgr.resolveSource('https://github.com/org/repo/tree/main/src/new-folder');\n// or clone entire repo:\nawait mgr.resolveSource('https://github.com/org/repo');","handlingStrategy":"validation","validationCode":"// After cloning, verify subdir exists before relying on it\nconst parsed = mgr.parseSource(url);\nif (parsed.subdir) {\n  // You can't check before clone, but you can pre-validate by listing remote refs\n  console.log(`Will expect subdirectory: ${parsed.subdir}`);\n  // After resolveSource succeeds, the subdir is guaranteed to exist\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await mgr.resolveSource(url);\n} catch (e) {\n  if (e.message.includes('not found in cloned repository')) {\n    // Retry without the subdirectory to clone the whole repo\n    const urlWithoutSubdir = url.replace(/\\/tree\\/[^/]+\\/.*$/, '');\n    console.log(`Retrying full repo clone: ${urlWithoutSubdir}`);\n    await mgr.resolveSource(urlWithoutSubdir);\n    return;\n  }\n  throw e;\n}","preventionTips":["Verify the subdirectory path exists in the target branch before using a deep-link URL.","Prefer cloning the whole repo over using subdirectory deep-links when unsure.","Pin to a tag where the subdirectory is known to exist."],"tags":["git","clone","subdirectory","filesystem"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}