evanw/esbuild · error · Error
Expected in mangle cache to map to either a string or false
Error message
Expected ${quote(key)} in mangle cache to map to either a string or false What it means
The `mangleCache` option maps property names to either their mangled replacement (a string) or to `false` (meaning 'do not mangle this property'). validateMangleCache() at lib/shared/common.ts:109 rejects any other value type (number, null, true, array, object). This keeps the cache round-trippable between builds.
Solutions
- Ensure every value in the mangleCache object is a string or exactly the boolean `false`.
- Feed back the mangleCache exactly as esbuild returned it in the previous result.
- If you must transform values, coerce to string or `false` explicitly before passing.
Example fix
// before
await build({ entryPoints: ['app.ts'], mangleProps: /^_/, mangleCache: { _secret: 0 } })
// after
await build({ entryPoints: ['app.ts'], mangleProps: /^_/, mangleCache: { _secret: false } }) Defensive patterns
Strategy: validation
Validate before calling
function sanitizeMangleCache(cache) {
if (!cache) return cache
const out = Object.create(null)
for (const key of Object.keys(cache)) {
const v = cache[key]
if (typeof v !== 'string' && v !== false) {
throw new Error(`mangleCache[${key}] must be string or false, got ${typeof v}`)
}
out[key] = v
}
return out
}
options.mangleCache = sanitizeMangleCache(options.mangleCache) Type guard
function isMangleCache(v): v is Record<string, string | false> {
if (!v || typeof v !== 'object') return false
return Object.values(v).every(x => typeof x === 'string' || x === false)
}
if (options.mangleCache && !isMangleCache(options.mangleCache)) {
throw new Error('invalid mangleCache')
} Prevention
- Pass the mangleCache from a previous build result through unchanged.
- Type the cache as Record<string, string | false> in your own code.
- Validate the cache after JSON round-trips, since those can introduce null/numbers.
When it happens
Trigger: Passing `mangleCache: { prop: 0 }`, `{ prop: null }`, `{ prop: true }`, or `{ prop: { x: 1 } }` to build()/context()/transform().
Common situations: Hand-editing or programmatically transforming a mangleCache returned by a previous build; serializing/deserializing the cache through a layer that coerces booleans; merging caches from multiple sources with non-conforming values.
Related errors
- Expected value for supported
- Expected value for to be a string, got instead
- Invalid banner file type
- Invalid charset
- Invalid color
AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09).
Data as JSON: /api/errors/05bbc67946998c36.
Report an issue: GitHub.
Appendix: source
Thrown at lib/shared/common.ts:118
return {
wasmURL,
wasmModule,
worker,
}
}
type MangleCache = Record<string, string | false>
function validateMangleCache(mangleCache: MangleCache | undefined): MangleCache | undefined {
let validated: MangleCache | undefined
if (mangleCache !== undefined) {
validated = Object.create(null) as MangleCache
for (let key in mangleCache) {
let value = mangleCache[key]
if (typeof value === 'string' || value === false) {
validated[key] = value
} else {
throw new Error(`Expected ${quote(key)} in mangle cache to map to either a string or false`)
}
}
}
return validated
}
type CommonOptions = types.BuildOptions | types.TransformOptions
function pushLogFlags(flags: string[], options: CommonOptions, keys: OptionKeys, isTTY: boolean, logLevelDefault: types.LogLevel): void {
let color = getFlag(options, keys, 'color', mustBeBoolean)
let logLevel = getFlag(options, keys, 'logLevel', mustBeString)
let logLimit = getFlag(options, keys, 'logLimit', mustBeInteger)
let logStyle = getFlag(options, keys, 'logStyle', mustBeString)
if (color !== void 0) flags.push(`--color=${color}`)
else if (isTTY) flags.push(`--color=true`); // This is needed to fix "execFileSync" which buffers stderr
flags.push(`--log-level=${logLevel || logLevelDefault}`)
flags.push(`--log-limit=${logLimit || 0}`)View on GitHub (pinned to f6058f8364)