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

  1. Reinstall with --next=<moduleCode> to use the latest main branch, which has the current file layout.
  2. Pin to a newer stable tag that was released after the restructure.
  3. Update bmad-modules.yaml's module_definition path to match the old tag's layout (if you control the registry).
  4. 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

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


AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13). Data as JSON: /api/errors/d4e1daf59ed363ad. Report an issue: GitHub.