jquense/yup · error · Error
Unable to clone ${src}
Error message
Unable to clone ${src} What it means
yup's cloneDeep (used when cloning schema option objects and values, e.g. default() / concat() / casting with structured cloning semantics) only knows how to clone plain objects, arrays, Date, RegExp, Map, Set and schemas. Anything else object-like that survives all instanceof checks (or non-Object exotic values reaching the else branch) hits `throw Error('Unable to clone ...')`.
Source
Thrown at src/util/cloneDeep.ts:40
seen.set(src, copy);
for (let i = 0; i < src.length; i++) copy[i] = clone(src[i], seen);
} else if (src instanceof Map) {
// Map
copy = new Map();
seen.set(src, copy);
for (const [k, v] of src.entries()) copy.set(k, clone(v, seen));
} else if (src instanceof Set) {
// Set
copy = new Set();
seen.set(src, copy);
for (const v of src) copy.add(clone(v, seen));
} else if (src instanceof Object) {
// Object
copy = {};
seen.set(src, copy);
for (const [k, v] of Object.entries(src)) copy[k] = clone(v, seen);
} else {
throw Error(`Unable to clone ${src}`);
}
return copy;
}
export default clone;
View on GitHub (pinned to ff31eee8a2)
Solutions
- Replace the unclonable value with a plain serializable one, or provide it via a function: `default(() => getMyObj())` so yup clones the result at use-time — preferably a plain object.
- Convert the value before it reaches the schema (e.g. WeakMap→Map, DOM node→its id, class instance→plain object via toJSON/spread).
- If the value is a legit plain object failing instanceof due to cross-realm origins, normalize it with Object.assign({}, src) before use.
- Check recent changes: often a new default()/meta() input introduced the exotic value; log the value shown in the message and trace its origin.
Example fix
// before
const schema = yup.object().shape({
ctx: yup.mixed().default(weakRefContext), // Unable to clone [object WeakMap]
});
// after
const schema = yup.object().shape({
ctx: yup.mixed().default(() => ({ id: weakRefContext.id })),
}); Defensive patterns
Strategy: validation
Validate before calling
// ensure schema default/oneOf values are clonable before use
function isClonable(v: unknown): boolean {
if (v == null || typeof v !== 'object') return true;
if (v instanceof Date || v instanceof RegExp || Array.isArray(v) || v instanceof Map || v instanceof Set) return true;
if (v.constructor === Object || v.constructor == null) return true;
return false; // class instances, WeakMaps, DOM nodes, functions-in-containers are risky
} Type guard
function isPlainObject(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null &&
(Object.getPrototypeOf(v) === Object.prototype || Object.getPrototypeOf(v) === null);
} Try / catch
try {
const out = schema.cast(input);
} catch (e) {
if (typeof e?.message === 'string' && e.message.startsWith('Unable to clone')) {
console.error('Unclonable schema option/value detected:', e.message);
}
} Prevention
- Keep schema defaults, oneOf values, and meta limited to JSON-serializable plain data.
- Pass side-effectful values as factory functions: default(() => makeObj()).
- Strip exotic values (WeakMap, DOM nodes, cross-realm objects) before they enter the schema.
- Test schema.cast/default paths in CI with the actual option objects used in production.
When it happens
Trigger: Passing an unclonable value into schema configuration that yup clones — e.g. `yup.string().default(() => someFunction)` is fine but `default(new WeakMap())`-style exotic objects, class instances that proxy weirdly, DOM nodes, or functions stored inside default/oneOf option objects; or circular structures in edge paths before the seen-map kicks in.
Common situations: Storing non-serializable objects (DOMNode, WeakMap, Symbol-keyed exotic, module namespace objects, worker/refs) in schema defaults or metadata; passing React refs or Vue reactive proxies into defaults; environment-specific objects (Buffer, cross-realm objects where instanceof fails).
Related errors
- either `then:` or `otherwise:` is required for `when()` cond
- conditions must return a schema object
- lazy() functions must return a valid schema
- ref must be a string, got:
- ref must be a non-empty string
AI-assisted analysis of jquense/yup@ff31eee8a2 (2026-08-31).
Data as JSON: /api/errors/936eb26bc10645d8.
Report an issue: GitHub.