jestjs/jest · error · TypeError
Jest: You can only define a single loader through…
Error message
Jest: You can only define a single loader through docblocks, got "${tsLoader.join(', ')}" What it means
Thrown as a TypeError by loadTSConfigFile when the jest-docblock parser returns an Array for the @jest-config-loader pragma. Docblock pragmas become arrays when the same tag is declared more than once in the file header, and the loader supports only a single loader.
Solutions
- Open the config file and remove all but one @jest-config-loader line
- Choose the loader you actually want (ts-node or esbuild-register) and keep only that one
- Run prettier/eslint with docblock awareness to catch duplicate pragmas in future
Example fix
/** * @jest-config-loader ts-node * @jest-config-loader esbuild-register */ // before: two loaders -> error /** * @jest-config-loader ts-node */ // after: single loader
Defensive patterns
Strategy: validation
Validate before calling
import { extract, parse } from 'jest-docblock';
import * as fs from 'node:fs';
const pragmas = parse(extract(fs.readFileSync('jest.config.ts', 'utf8')));
if (Array.isArray(pragmas['jest-config-loader'])) {
throw new Error('Duplicate @jest-config-loader pragma detected');
} Type guard
function hasSingleLoaderPragma(pragmas: Record<string, unknown>): boolean {
const v = pragmas['jest-config-loader'];
return v === undefined || typeof v === 'string';
} Prevention
- Keep a single docblock header in the config file
- Lint duplicate pragmas in a precommit hook
- When merging config snippets, deduplicate docblock pragmas explicitly
When it happens
Trigger: Having two or more '@jest-config-loader' lines in the jest.config.ts/.cts docblock header, e.g. one declaring ts-node and another esbuild-register.
Common situations: Merging config snippets from different sources without deduplicating the docblock; copying examples that each carried their own loader pragma; tooling that auto-injects pragmas.
Related errors
- Jest: ' ' is not a valid TypeScript configuration loader.
- Jest: ' ' is required for the TypeScript configuration…
- jest.config.mts requires native TypeScript support. Ensure…
- Jest: Failed to parse the TypeScript config file
- Can't find a root directory while resolving a config file…
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/443f73b6c86e855a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/jest-config/src/readConfigFileAndSetRootDir.ts:163
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 8e6d128e4a)