facebook/docusaurus · error · Error

Looks like the changelog plugin didn't detect Docusaurus cha

Error message

Looks like the changelog plugin didn't detect Docusaurus changelog files

What it means

Thrown by getChangelogFiles() in the Docusaurus website's custom changelog plugin when safeGlobby finds fewer than 2 files matching `CHANGELOG(-v[0-9]*)?.md` at the monorepo root (path.resolve(__dirname, '../../../..')). The plugin expects at least the main CHANGELOG.md plus one versioned CHANGELOG-vN.md. This is an internal safeguard for the Docusaurus project's own website, not a user-facing API.

Source

Thrown at website/src/plugins/changelog/index.ts:32

  normalizeUrl,
  safeGlobby,
} from '@docusaurus/utils';
import {createBlogFiles, toChangelogEntries} from './utils';

export {validateOptions} from '@docusaurus/plugin-content-blog';

const MonorepoRoot = path.resolve(path.join(__dirname, '../../../..'));

const ChangelogFilePattern = 'CHANGELOG(-v[0-9]*)?.md';

async function getChangelogFiles() {
  const files = await safeGlobby([ChangelogFilePattern], {
    cwd: MonorepoRoot,
  });
  // As of today, there are 2 changelog files
  // and this is only going to increase
  if (files.length < 2) {
    throw new Error(
      "Looks like the changelog plugin didn't detect Docusaurus changelog files",
    );
  }
  // Note: the returned file order doesn't matter.
  return files;
}

function readChangelogFile(filename: string) {
  return fs.readFile(path.join(MonorepoRoot, filename), 'utf-8');
}

async function loadChangelogEntries(changelogFiles: string[]) {
  const filesContent = await Promise.all(changelogFiles.map(readChangelogFile));
  return toChangelogEntries(filesContent);
}

const ChangelogPlugin: typeof pluginContentBlog =
  async function ChangelogPlugin(context, options) {

View on GitHub (pinned to 3f483e80e3)

Solutions

  1. Confirm CHANGELOG.md and at least one CHANGELOG-vN.md exist at the monorepo root: `ls CHANGELOG*.md`.
  2. If files were renamed, either restore the expected names or update ChangelogFilePattern to match.
  3. If the plugin file moved, fix the relative '../../../..' in MonorepoRoot so it still points at the repo root.
  4. For your own project this plugin is not used — only the Docusaurus repo's own website hits this; copy the pattern but adjust the threshold/pattern to your project.

Example fix

// before
const ChangelogFilePattern = 'CHANGELOG(-v[0-9]*)?.md';
if (files.length < 2) { throw ... }
// after (adjust to your project's reality)
const ChangelogFilePattern = 'CHANGES.md';
if (files.length < 1) { throw ... }
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'fs-extra';
import path from 'path';

async function assertChangelogFiles(root: string, minCount = 2) {
  const {default: globby} = await import('globby');
  const files = await globby(['CHANGELOG(-v[0-9]*)?.md'], {cwd: root});
  if (files.length < minCount) {
    throw new Error(
      `Expected >= ${minCount} changelog files at ${root}, found ${files.length}: ${files.join(', ') || 'none'}`,
    );
  }
}

// await assertChangelogFiles(path.resolve(__dirname, '../../..'));

Prevention

When it happens

Trigger: Building the Docusaurus website when CHANGELOG files are missing, gitignored in a way that globby skips them, renamed, or when the monorepo root resolution (../../../.. from website/src/plugins/changelog) is wrong due to a moved file.

Common situations: Running the website build in a shallow/partial checkout that excluded CHANGELOG files; a repo restructure that moved the changelog plugin or changed the monorepo layout; someone deleted a versioned changelog during a cleanup.

Related errors


AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12). Data as JSON: /api/errors/7a1e54ddbf44b448. Report an issue: GitHub.