{"id":"6b66a346fcbf7e84","repo":"babel/babel","slug":"msg-proploc-must-be-null-undefined-a-boolean","errorCode":null,"errorMessage":"${msg(propLoc)} must be null, undefined, a boolean, a string, or a number.","messagePattern":"(.+?) must be null, undefined, a boolean, a string, or a number\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/babel-core/src/config/validation/option-assertions.ts","lineNumber":156,"sourceCode":"    if (typeof obj.name !== \"string\") {\n      throw new Error(\n        `${msg(loc)} set but does not contain \"name\" property string`,\n      );\n    }\n\n    for (const prop of Object.keys(obj)) {\n      const propLoc = access(loc, prop);\n      const value = obj[prop];\n      if (\n        value != null &&\n        typeof value !== \"boolean\" &&\n        typeof value !== \"string\" &&\n        typeof value !== \"number\"\n      ) {\n        // NOTE(logan): I'm limiting the type here so that we can guarantee that\n        // the \"caller\" value will serialize to JSON nicely. We can always\n        // allow more complex structures later though.\n        throw new Error(\n          `${msg(\n            propLoc,\n          )} must be null, undefined, a boolean, a string, or a number.`,\n        );\n      }\n    }\n  }\n  // @ts-expect-error todo(flow->ts)\n  return value;\n}\n\nexport function assertInputSourceMap(\n  loc: OptionPath,\n  value: unknown,\n): RootInputSourceMapOption {\n  if (\n    value !== undefined &&\n    typeof value !== \"boolean\" &&","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/babel/babel/blob/06b6eae39da4ce0689fad64e2c48a6375a464208/packages/babel-core/src/config/validation/option-assertions.ts#L138-L174","documentation":"Thrown by assertCallerMetadata (option-assertions.ts:156) when iterating the caller object's properties. Each property value must be null, undefined, a boolean, a string, or a number — Babel serializes caller metadata (e.g. for caching/logging) and complex values like objects, arrays, or functions break that contract. The offending property path is included via msg(propLoc).","triggerScenarios":"Setting `caller: { name: 'x', config: { foo: 1 } }` or `caller: { name: 'x', items: [1,2] }` or `caller: { name: 'x', fn: () => {} }`. The loop at option-assertions.ts:144 detects a value that is not null/undefined/boolean/string/number.","commonSituations":"Passing a nested config object or array as a caller property expecting plugins to read it; storing a function reference in caller metadata; spreading a complex tool config into caller.","solutions":["Keep caller property values to primitives (boolean, string, number) or null/undefined.","Flatten nested config into named primitive properties (e.g. `targetESVersion: 2020` instead of `target: { esVersion: 2020 }`).","If a plugin needs complex caller data, encode it as a JSON string and parse inside the plugin."],"exampleFix":"// before\nbabel.transformSync(code, { caller: { name: 'tool', opts: { loose: true } } });\n// after\nbabel.transformSync(code, { caller: { name: 'tool', loose: true } });","handlingStrategy":"type-guard","validationCode":"function sanitizeCaller(caller) {\n  const out = {};\n  for (const [k, v] of Object.entries(caller)) {\n    if (v == null || typeof v === 'boolean' || typeof v === 'string' || typeof v === 'number') {\n      out[k] = v;\n    }\n  }\n  return out;\n}","typeGuard":"function isPrimitiveCallerValue(v): boolean {\n  return v == null || ['boolean','string','number'].includes(typeof v);\n}","tryCatchPattern":"try {\n  babel.transformSync(code, opts);\n} catch (e) {\n  if (e.message.includes('must be null, undefined, a boolean, a string, or a number')) {\n    const c = {};\n    for (const [k, v] of Object.entries(opts.caller)) {\n      if (v == null || typeof v !== 'object') c[k] = v;\n    }\n    babel.transformSync(code, { ...opts, caller: c });\n  } else throw e;\n}","preventionTips":["Keep caller properties to primitives only.","Flatten nested objects into named primitive fields.","Encode complex data as a JSON string if a plugin must read it."],"tags":["options","caller","validation","serialization"],"analyzedSha":"06b6eae39da4ce0689fad64e2c48a6375a464208","analyzedAt":"2026-08-03T20:13:43.465Z","schemaVersion":2}