{"record":{"id":"ccfbbd300b9a0876","repo":"vitejs/vite","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":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vite/src/node/utils.ts","lineNumber":1575,"sourceCode":"      )\n      continue\n    }\n\n    merged[key] = value\n  }\n  return merged\n}\n\nexport function mergeConfig<\n  D extends Record<string, any>,\n  O extends Record<string, any>,\n>(\n  defaults: D extends Function ? never : D,\n  overrides: O extends Function ? never : O,\n  isRoot = true,\n): Record<string, any> {\n  if (typeof defaults === 'function' || typeof overrides === 'function') {\n    throw new Error(`Cannot merge config in form of callback`)\n  }\n\n  return mergeConfigRecursively(defaults, overrides, isRoot ? '' : '.')\n}\n\nfunction mergeInput(a?: InputOption, b?: InputOption): InputOption | undefined {\n  if (!a) return b\n  if (!b) return a\n\n  if (typeof a === 'string' && typeof b === 'string') {\n    return [a, b]\n  }\n  if (Array.isArray(a) && (typeof b === 'string' || Array.isArray(b))) {\n    return [...a, ...(Array.isArray(b) ? b : [b])]\n  }\n  if (Array.isArray(b) && (typeof a === 'string' || Array.isArray(a))) {\n    return [...(Array.isArray(a) ? a : [a]), ...b]\n  }","sourceCodeStart":1557,"sourceCodeEnd":1593,"githubUrl":"https://github.com/vitejs/vite/blob/b4d66fee14d970f45b8a6f3d7d6aee73ca9b88ab/packages/vite/src/node/utils.ts#L1557-L1593","documentation":"Thrown by mergeConfig() when either the defaults or the overrides argument is a function. mergeConfig merges two plain config objects; the functional form of defineConfig/mergeConfig (which returns a function) is not accepted here and must be resolved to a plain object first.","triggerScenarios":"Calling mergeConfig(fn, overrides) or mergeConfig(defaults, fn) where fn is a function — e.g. the result of defineConfig(async () => ({...})) or a mergeConfig callback. The check `typeof ... === 'function'` is at utils.ts:1574.","commonSituations":"Programmatically merging a base config that was authored with the callback form of defineConfig. Passing an un-invoked mergeConfig callback (mergeConfig also supports mergeConfig(callback) at the top level, but two-argument mergeConfig does not).","solutions":["Resolve the function to a plain object before merging: invoke the defineConfig callback (await if async) to get the config object.","Use mergeConfig with plain objects only; do not pass the callback form as an argument.","If you need the functional form, call mergeConfig(callback) with a single function argument at the top level instead of merging two values."],"exampleFix":"// before\nconst base = defineConfig(async () => ({ plugins: [a] }))\nmergeConfig(base, { plugins: [b] }) // throws (base is a function)\n// after\nconst baseObj = await base()\nmergeConfig(baseObj, { plugins: [b] })","handlingStrategy":"type-guard","validationCode":"function isPlainConfig(v: unknown): v is Record<string, any> {\n  return v != null && typeof v !== 'function'\n}\nif (!isPlainConfig(defaults) || !isPlainConfig(overrides)) {\n  throw new TypeError('mergeConfig needs plain objects, not functions')\n}","typeGuard":"function isPlainConfigObject(v: unknown): v is Record<string, any> {\n  return v != null && typeof v === 'object' && typeof v !== 'function'\n}","tryCatchPattern":null,"preventionTips":["Resolve defineConfig/mergeConfig callbacks to plain objects before calling two-arg mergeConfig.","Reserve the functional form for the single-argument mergeConfig(callback) entry point."],"tags":["configuration","merge-config","type-mismatch"],"backgroundTag":null,"analyzedSha":"b4d66fee14d970f45b8a6f3d7d6aee73ca9b88ab","analyzedAt":"2026-08-11T11:49:19.515Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}