jestjs/jest · error · TypeError
Cannot merge config in form of callback
Error message
Cannot merge config in form of callback
What it means
mergeConfig (index.ts:66-78) deep-merges two plain config objects. It inspects their properties directly, so it cannot operate on the function/async-function config form that defineConfig supports. The runtime guard at index.ts:73-75 throws a TypeError if either argument is callable, matching the documented limitation that mergeConfig only accepts object configs.
Solutions
- Resolve the function to an object first: const base = await baseConfig(); then mergeConfig(base, overrides).
- Restructure so both arguments to mergeConfig are plain objects (compute dynamic values before merging).
- For env-dependent overrides, apply them inside a single callback config rather than merging two callbacks.
Example fix
// before
const base = () => ({ testEnvironment: 'node' });
mergeConfig(base, { verbose: true });
// after
const base = { testEnvironment: 'node' };
mergeConfig(base, { verbose: true });
// or resolve first:
const base = await baseFn();
mergeConfig(base, { verbose: true }); Defensive patterns
Strategy: type-guard
Validate before calling
function safeMergeConfig<D extends object, O extends object>(d: D | (() => D), o: O | (() => O)) {
if (typeof d === 'function' || typeof o === 'function') {
throw new TypeError('Cannot mergeConfig function-form configs; resolve them to objects first');
}
return mergeConfig(d, o);
} Type guard
function isPlainConfigObject<T extends object>(c: unknown | (() => T) | (() => Promise<T>)): c is T {
return typeof c === 'object' && c !== null && typeof (c as any) !== 'function';
} Prevention
- Resolve function/async configs to objects before calling mergeConfig.
- Keep base/override configs as plain objects; put env-conditional logic elsewhere.
- Type the mergeConfig inputs as objects (not the function union) to catch this at compile time.
When it happens
Trigger: Calling mergeConfig(() => ({...}), {...}); mergeConfig({...}, async () => ({...})); passing a jest.config.ts that exports a function into mergeConfig; chaining defineConfig(fn) outputs into mergeConfig.
Common situations: Writing a base/override config split where one side is a function for env-based config; refactoring a config from object to callback form without updating the merge call; trying to merge presets defined as functions.
Related errors
- Cannot find module
- Could not resolve a module for a custom reporter. Module…
- `.each` must be called with an Array or Tagged Template…
- path must be a string or array
- value must be a function
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/4af9439269eb5bb4.
Report an issue: GitHub.
Appendix: source
Thrown at packages/jest-config/src/index.ts:74
export function defineConfig(config: UserConfigFnObject): UserConfigFnObject;
export function defineConfig(config: UserConfigFnPromise): UserConfigFnPromise;
export function defineConfig(config: UserConfigFn): UserConfigFn;
export function defineConfig(config: UserConfigExport): UserConfigExport {
return config;
}
/**
* Merges two configuration objects, where the second object takes precedence over the first one.
*/
export function mergeConfig<
D extends UserConfigExport,
O extends UserConfigExport,
>(
defaults: D extends Function ? never : D,
overrides: O extends Function ? never : O,
): JestTestConfigObject {
if (typeof defaults === 'function' || typeof overrides === 'function') {
throw new TypeError('Cannot merge config in form of callback');
}
return deepMerge.all([defaults, overrides]);
}
export async function readConfig(
argv: Config.Argv,
packageRootOrConfig: string | Config.InitialOptions,
// Whether it needs to look into `--config` arg passed to CLI.
// It only used to read initial config. If the initial config contains
// `project` property, we don't want to read `--config` value and rather
// read individual configs for every project.
skipArgvConfigOption?: boolean,
parentConfigDirname?: string | null,
projectIndex = Number.POSITIVE_INFINITY,
skipMultipleConfigError = false,
): Promise<ReadConfig> {
const {config: initialOptions, configPath} = await readInitialOptions(View on GitHub (pinned to 8e6d128e4a)