bmad-code-org/BMAD-METHOD · error · Error
Module '${moduleCode}' was downloaded but its module definit
Error message
Module '${moduleCode}' was downloaded but its module definition was not found. Expected '${moduleDefinitionPath}' to exist in ${versionHint}, but it is missing. The repository may have been restructured after this release was tagged.${channelHint} What it means
Thrown by findExternalModuleSource() when a module was successfully cloned but no module.yaml file can be found at the registry-configured moduleDefinition path, nor in fallback locations (skills/, src/, repo root). This typically means the stable tag predates a repository restructuring where module files were moved.
Source
Thrown at tools/installer/modules/external-manager.js:581
}
}
// Check repo root as last fallback
const rootCandidate = path.join(cloneDir, 'module.yaml');
if (await fs.pathExists(rootCandidate)) {
return path.dirname(rootCandidate);
}
// Nothing found: the cloned ref does not contain a recognizable module structure.
// This happens when a stable tag predates a module restructure (e.g. the repo
// moved files from payload/ to skills/ after the tag was cut). Returning a
// non-existent path silently causes a confusing ENOENT deep inside copyModuleWithFiltering;
// throw a descriptive error here instead so the user knows what happened and how to recover.
const resolution = ExternalModuleManager._resolutions.get(moduleCode);
const versionHint = resolution?.version ? `version ${resolution.version}` : 'the cloned version';
const channelHint =
resolution?.channel === 'stable' ? ` Try reinstalling with \`--next=${moduleCode}\` to use the latest main branch instead.` : '';
throw new Error(
`Module '${moduleCode}' was downloaded but its module definition was not found. ` +
`Expected '${moduleDefinitionPath}' to exist in ${versionHint}, but it is missing. ` +
`The repository may have been restructured after this release was tagged.${channelHint}`,
);
}
/**
* Resolve a marketplace-plugin registry module to an installable plugin
* definition. Clones the repo (respecting the channel plan), reads its
* .claude-plugin/marketplace.json, and runs the PluginResolver against the
* plugin matching this module. The result (skillPaths + module.yaml +
* module-help.csv) is cached so install() can copy the resolved skill dirs.
*
* @param {string} moduleCode - Code of the external module
* @param {Object} options - Options passed to cloneExternalModule
* @returns {Promise<Object|null>} ResolvedModule from PluginResolver, or null
* when the module is not a marketplace plugin or cannot be resolved.
*/View on GitHub (pinned to b70486b9bd)
Solutions
- Reinstall with --next=<moduleCode> to use the latest main branch, which has the current file layout.
- Pin to a newer stable tag that was released after the restructure.
- Update bmad-modules.yaml's module_definition path to match the old tag's layout (if you control the registry).
- Verify the module's repository structure on GitHub for the tagged version.
Example fix
# before — old stable tag predates restructure npx bmad-method install # Error: module definition not found in version v1.0.0 # after — use latest main npx bmad-method install --next=my-module # or pin a newer release npx bmad-method install --pin my-module=v2.0.0
Defensive patterns
Strategy: fallback
Validate before calling
// Check if the module's definition path exists at the target tag before committing to stable
const { execSync } = require('child_process');
function checkFileAtTag(url, tag, filePath) {
try {
execSync(`git ls-remote --exit-code ${url} refs/tags/${tag}`, { stdio: 'ignore' });
// For a deeper check, use the GitHub API to verify the file exists at the tag
return true;
} catch {
return false;
}
}
// Prefer --next for modules that have recently restructured
const moduleInfo = await extMgr.getModuleByCode(moduleCode);
if (moduleInfo && recentlyRestructured(moduleInfo)) {
options.channelOptions = { nextSet: new Set([moduleCode]) };
} Try / catch
try {
await officialModules.findModuleSource(moduleCode, options);
} catch (e) {
if (e.message.includes('module definition was not found')) {
// Switch to --next to get the current repo layout
console.log('Stable tag has old layout. Retrying with --next...');
await officialModules.findModuleSource(moduleCode, {
...options,
channelOptions: { nextSet: new Set([moduleCode]) },
});
return;
}
throw e;
} Prevention
- Use --next for modules that have recently undergone repository restructuring.
- Pin to tags known to have the current file layout.
- Keep the registry's module_definition path in sync with the repository structure.
- When cutting stable tags, ensure module.yaml exists at the expected path.
When it happens
Trigger: Installing a module from a 'stable' channel tag that was cut before the repo moved its module.yaml (e.g., from payload/ to skills/). After cloning, findExternalModuleSource checks moduleInfo.moduleDefinition, then skills/module.yaml, src/module.yaml, and root — all miss.
Common situations: An old stable tag (e.g., v1.0.0) was released before a major repo restructure; the moduleDefinition path in bmad-modules.yaml is stale; a tag was cut from a branch that didn't have the module layout yet.
Related errors
- Unsafe ref name: ${JSON.stringify(ref)}
- Tag '${planEntry.pin}' not found in ${parsed.owner}/${parsed
- Failed to clone external module '${moduleCode}' at ${resolve
- Unsafe ref name: ${JSON.stringify(ref)}
- Not a valid Git URL or local path
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/d4e1daf59ed363ad.
Report an issue: GitHub.