vitest-dev/vitest · error · Error
Failed to load custom "defines
Error message
Failed to load custom "defines": ${error.message} What it means
Vitest serializes config.define into a JS expression string (serializedDefines) and runs it via runInThisContext to inject global constants into the worker. If that generated JS fails to parse/evaluate, the original error is caught and re-thrown wrapped as 'Failed to load custom defines: <message>'. This runs in the base (non-vm) worker path.
Solutions
- Ensure every define value is JSON-serializable (strings, numbers, booleans, plain objects/arrays).
- Avoid functions, BigInt, circular references, and Symbols in test.define / vite.define.
- Read the wrapped error.message (the inner exception) to identify which define key broke.
- If you need runtime values, import them from a module instead of inlining via define.
Example fix
// before
export default defineConfig({
test: { define: { __fn: () => 1 } }
})
// after
export default defineConfig({
test: { define: { __flag: JSON.stringify('on') } }
}) Defensive patterns
Strategy: validation
Validate before calling
import { isJSON } from './checks'
function validateDefines(obj) {
for (const [k, v] of Object.entries(obj)) {
try { JSON.parse(JSON.stringify(v)) } catch { throw new Error(`define '${k}' is not serializable`) }
}
} Type guard
function isJsonSerializable(v) {
try { JSON.stringify(v); return true } catch { return false }
} Prevention
- Keep define values to primitives and plain JSON structures.
- Avoid functions, BigInt, Symbols, and circular refs in define.
- Validate the serializedDefines string during config build.
When it happens
Trigger: The define config produces values whose JSON serialization is not valid as the body of an IIFE in the worker context — e.g. a function, a circular object, a BigInt, or a value whose custom toJSON returns something unparseable. runInThisContext throws SyntaxError or TypeError, which gets wrapped.
Common situations: Putting non-serializable values in vitest.config define (functions, class instances, symbols), or a plugin mutating define at runtime to inject something that is not plain JSON.
Related errors
- Failed to load custom "defines
- Cannot provide " " because it's not serializable.
- "snapshotFormat.compareKeys" function is not supported.
- Tag " ": retry.condition function cannot be used inside a…
- Access denied to " ". See Vite config documentation for…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/50c0eaeca8f6e8e2.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/workers/base.ts:146
const { ctx } = state
state.environment = _currentEnvironment
state.durations.environment = _environmentTime
// state has new context, but we want to reuse existing ones
state.evaluatedModules = evaluatedModules
state.moduleExecutionInfo = moduleExecutionInfo
provideWorkerState(globalThis, state)
// we could load @vite/env, but it would take ~8ms, while this takes ~0,02ms
if (state.config.serializedDefines) {
try {
runInThisContext(`(() =>{\n${state.config.serializedDefines}})()`, {
lineOffset: 1,
filename: 'virtual:load-defines.js',
})
}
catch (error: any) {
throw new Error(`Failed to load custom "defines": ${error.message}`)
}
}
if (ctx.invalidates) {
ctx.invalidates.forEach((filepath) => {
const modules = state.evaluatedModules.fileToModulesMap.get(filepath) || []
modules.forEach((module) => {
state.evaluatedModules.invalidateModule(module)
})
})
}
ctx.files.forEach((i) => {
const filepath = i.filepath
const modules = state.evaluatedModules.fileToModulesMap.get(filepath) || []
modules.forEach((module) => {
state.evaluatedModules.invalidateModule(module)
})
})View on GitHub (pinned to 1fa9837ec2)