bmad-code-org/BMAD-METHOD · error · Error

[rehype-markdown-links] Could not detect content directory f

Error message

[rehype-markdown-links] Could not detect content directory for: ${currentFilePath}

What it means

Thrown by the rehype-markdown-links plugin when detectContentDir can't find a content root for the current markdown file. detectContentDir walks the file's path segments looking for 'src/content/docs' (Astro/Starlight convention) or a standalone 'docs' directory; returning null means neither pattern matched, so the plugin cannot compute output URLs.

Source

Thrown at website/src/rehype-markdown-links.js:35

/**
 * @param {Object} options
 * @param {string} options.base - Site base path (e.g., '/BMAD-METHOD/')
 * @param {string} [options.contentDir] - Absolute path to content root; auto-detected if omitted
 */
export default function rehypeMarkdownLinks(options = {}) {
  const base = options.base || '/';
  const normalizedBase = base === '/' ? '' : base.replace(/\/$/, '');

  return (tree, file) => {
    // The current file's absolute path on disk, set by Astro's markdown pipeline
    const currentFilePath = file.path;
    if (!currentFilePath) return;

    // Auto-detect content root: walk up from current file to find src/content/docs
    const contentDir = options.contentDir || detectContentDir(currentFilePath);
    if (!contentDir) {
      throw new Error(`[rehype-markdown-links] Could not detect content directory for: ${currentFilePath}`);
    }

    visit(tree, 'element', (node) => {
      if (node.tagName !== 'a' || typeof node.properties?.href !== 'string') {
        return;
      }

      const href = node.properties.href;

      // Skip external links (including protocol-relative URLs like //cdn.example.com)
      if (href.includes('://') || href.startsWith('//') || href.startsWith('mailto:') || href.startsWith('tel:')) {
        return;
      }

      // Split href into path vs query+fragment suffix
      const delimIdx = findFirstDelimiter(href);
      const linkPath = delimIdx === -1 ? href : href.substring(0, delimIdx);
      const suffix = delimIdx === -1 ? '' : href.substring(delimIdx);

View on GitHub (pinned to b70486b9bd)

Solutions

  1. Pass contentDir explicitly in the plugin options: rehypeMarkdownLinks({ base, contentDir: '/abs/path/to/content' }).
  2. Ensure markdown files live under src/content/docs (Astro) or a docs/ directory so detectContentDir matches.
  3. If the site was restructured, update detectContentDir's pattern or the contentDir option to match the new layout.

Example fix

// before
//   rehypeMarkdownLinks({ base })   // auto-detect fails on restructured site
//
// after
//   rehypeMarkdownLinks({
//     base,
//     contentDir: path.resolve(process.cwd(), 'website/src/content/docs'),
//   })
Defensive patterns

Strategy: validation

Validate before calling

const contentDir = options.contentDir || detectContentDir(currentFilePath);
if (!contentDir) {
  throw new Error(`Configure rehypeMarkdownLinks({ contentDir: '...' }) for non-standard layouts.`);
}
// pass contentDir explicitly in the plugin options
rehypeMarkdownLinks({ base, contentDir });

Type guard

function hasContentDir(filePath) {
  const seg = filePath.split(path.sep);
  for (let i = seg.length - 1; i >= 2; i--) {
    if (seg[i - 2] === 'src' && seg[i - 1] === 'content' && seg[i] === 'docs') return true;
  }
  return seg.includes('docs');
}

Try / catch

try {
  astroConfig.rehypePlugins.push([rehypeMarkdownLinks, { base, contentDir }]);
} catch (e) {
  if (/Could not detect content directory/.test(e.message)) {
    // fall back to explicit contentDir resolved from process.cwd()
  } else { throw e; }
}

Prevention

When it happens

Trigger: Running the Astro build on a markdown file whose absolute path contains neither src/content/docs nor a docs segment. Calling the plugin outside its expected content-root layout (file.path is set, which skips the early return, but no recognized root is found above it).

Common situations: Restructuring the website content directory away from src/content/docs or docs; running the plugin against files outside the content root; build config changed srcDir; new collection location not covered by detectContentDir's patterns.

Related errors


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