jestjs/jest · error · TypeError

Jest: You can only define a single loader through docblocks,

Error message

Jest: You can only define a single loader through docblocks, got "${tsLoader.join(', ')}"

What it means

When loading a TS config via a loader, Jest reads the `@jest-config-loader` pragma from the docblock at the top of the config file. The pragma must name exactly one loader ('ts-node' or 'esbuild-register'). If the docblock contains the pragma twice, jest-docblock returns an array, and this TypeError is thrown.

Source

Thrown at packages/jest-config/src/readConfigFileAndSetRootDir.ts:162

const loadDocblockPragmasInConfig = (configPath: string): Pragmas => {
  const docblockPragmas = parse(extract(fs.readFileSync(configPath, 'utf8')));
  return docblockPragmas;
};

const loadTSConfigFile = async (
  configPath: string,
): Promise<Config.InitialOptions> => {
  // Get registered TypeScript compiler instance
  const docblockPragmas = loadDocblockPragmasInConfig(configPath);
  const tsLoader = docblockPragmas['jest-config-loader'] || 'ts-node';
  const docblockTSLoaderOptions = docblockPragmas['jest-config-loader-options'];

  if (typeof docblockTSLoaderOptions === 'string') {
    extraTSLoaderOptions = JSON.parse(docblockTSLoaderOptions);
  }
  if (Array.isArray(tsLoader)) {
    throw new TypeError(
      `Jest: You can only define a single loader through docblocks, got "${tsLoader.join(
        ', ',
      )}"`,
    );
  }

  const registeredCompiler = await getRegisteredCompiler(
    tsLoader as TsLoaderModule,
  );
  registeredCompiler.enabled(true);

  let configObject = interopRequireDefault(require(configPath)).default;

  // In case the config is a function which imports more Typescript code
  if (typeof configObject === 'function') {
    configObject = await configObject();
  }

View on GitHub (pinned to f49721c78e)

Solutions

  1. Keep only one @jest-config-loader line in the docblock
  2. Remove the docblock entirely to use the default 'ts-node' loader

Example fix

/**
 * @jest-config-loader ts-node
 * @jest-config-loader esbuild-register
 */
// becomes
/**
 * @jest-config-loader ts-node
 */
Defensive patterns

Strategy: validation

Validate before calling

import {parse, extract} from 'jest-docblock';
import * as fs from 'node:fs';
const pragmas = parse(extract(fs.readFileSync('jest.config.ts', 'utf8')));
const loader = pragmas['jest-config-loader'];
if (Array.isArray(loader)) {
  throw new Error('Multiple @jest-config-loader pragmas detected');
}

Prevention

When it happens

Trigger: Writing `@jest-config-loader ts-node` and `@jest-config-loader esbuild-register` in the same docblock header of jest.config.ts.

Common situations: Copy-pasting a docblock from two sources; merging config snippets without deduplicating pragmas.

Related errors


AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03). Data as JSON: /data/errors/443f73b6c86e855a.json. Report an issue: GitHub.