{"id":"4af9439269eb5bb4","repo":"jestjs/jest","slug":"cannot-merge-config-in-form-of-callback","errorCode":null,"errorMessage":"Cannot merge config in form of callback","messagePattern":"Cannot merge config in form of callback","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/jest-config/src/index.ts","lineNumber":74,"sourceCode":"export function defineConfig(config: UserConfigFnObject): UserConfigFnObject;\nexport function defineConfig(config: UserConfigFnPromise): UserConfigFnPromise;\nexport function defineConfig(config: UserConfigFn): UserConfigFn;\nexport function defineConfig(config: UserConfigExport): UserConfigExport {\n  return config;\n}\n\n/**\n * Merges two configuration objects, where the second object takes precedence over the first one.\n */\nexport function mergeConfig<\n  D extends UserConfigExport,\n  O extends UserConfigExport,\n>(\n  defaults: D extends Function ? never : D,\n  overrides: O extends Function ? never : O,\n): JestTestConfigObject {\n  if (typeof defaults === 'function' || typeof overrides === 'function') {\n    throw new TypeError('Cannot merge config in form of callback');\n  }\n\n  return deepMerge.all([defaults, overrides]);\n}\n\nexport async function readConfig(\n  argv: Config.Argv,\n  packageRootOrConfig: string | Config.InitialOptions,\n  // Whether it needs to look into `--config` arg passed to CLI.\n  // It only used to read initial config. If the initial config contains\n  // `project` property, we don't want to read `--config` value and rather\n  // read individual configs for every project.\n  skipArgvConfigOption?: boolean,\n  parentConfigDirname?: string | null,\n  projectIndex = Number.POSITIVE_INFINITY,\n  skipMultipleConfigError = false,\n): Promise<ReadConfig> {\n  const {config: initialOptions, configPath} = await readInitialOptions(","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/jest-config/src/index.ts#L56-L92","documentation":"jest-config's `mergeConfig` (packages/jest-config/src/index.ts:66) does a deepmerge of two config objects, so it must inspect their properties; it throws a TypeError if either argument is a function (a 'callback-style' config), because a function is opaque until called and merging it is undefined behavior. The runtime guard is at index.ts:73.","triggerScenarios":"Calling `mergeConfig(() => baseConfig, overrides)` or `mergeConfig(base, async () => overrides)` — passing a function config (the form supported by jest.config.js exports) into mergeConfig.","commonSituations":"Building a base config programmatically and forwarding the callback export directly to mergeConfig; wrapping a vendor config that exports a function.","solutions":["Resolve the callback yourself first: `const base = typeof baseOrFn === 'function' ? await baseOrFn() : baseOrFn;` then call `mergeConfig(base, overrides)`.","Author the base config as a plain object (not a function export) when you intend to merge it.","Use `defineConfig` only as a type helper; it does not unwrap callbacks for merging."],"exampleFix":"// before\nconst base = () => ({ testEnvironment: 'node' });\nmodule.exports = mergeConfig(base, { verbose: true }); // throws\n\n// after\nconst base = { testEnvironment: 'node' };\nmodule.exports = mergeConfig(base, { verbose: true });","handlingStrategy":"validation","validationCode":"import {mergeConfig} from 'jest-config';\nfunction safeMerge(d: any, o: any) {\n  if (typeof d === 'function' || typeof o === 'function') {\n    throw new TypeError('Cannot merge a callback config; resolve it to an object first');\n  }\n  return mergeConfig(d, o);\n}","typeGuard":"const isPlainConfigObject = (c: unknown): c is Record<string, unknown> =>\n  c !== null && typeof c === 'object' && typeof (c as any) !== 'function';","tryCatchPattern":"try {\n  return mergeConfig(defaults, overrides);\n} catch (e) {\n  if (e instanceof TypeError && /callback/.test(e.message)) {\n    // resolve callbacks to objects, then retry with plain objects\n    const d = typeof defaults === 'function' ? await defaults() : defaults;\n    const o = typeof overrides === 'function' ? await overrides() : overrides;\n    return mergeConfig(d, o);\n  }\n  throw e;\n}","preventionTips":["Author base configs as plain objects when you plan to merge.","Resolve function exports before calling mergeConfig.","Remember defineConfig is a type helper, not an unwrap."],"tags":["jest-config","mergeconfig","config","typeerror"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}