diff --git a/lib/clone.js b/lib/clone.js index c05a32a..fec88d7 100755 --- a/lib/clone.js +++ b/lib/clone.js @@ -173,10 +173,12 @@ internals.base = function (obj, baseProto, options) { } // Can only be covered in node 21+ /* $lab:coverage:off$ */ - else if (baseProto === Types.error && internals.structuredCloneExists) { - const err = structuredClone(obj); // Needed to copy internal stack state + else if (baseProto === Types.error && internals.structuredCloneExists && + (proto === baseProto || Error.isPrototypeOf(proto.constructor))) { // Don't match Util.inherit() subclassed errors + + const err = structuredClone(obj); // Needed to copy internal stack state if (Object.getPrototypeOf(err) !== proto) { - Object.setPrototypeOf(err, proto); // Fix prototype + Object.setPrototypeOf(err, proto); // Fix prototype } return err; diff --git a/test/clone.js b/test/clone.js index 7035ae7..2ed00f2 100755 --- a/test/clone.js +++ b/test/clone.js @@ -731,6 +731,35 @@ describe('clone()', () => { expect(b.stack).to.equal(a.stack); }); + it('clones Error with function property', () => { + + const a = new Error('hello'); + a.fun = new Function(); + + const b = Hoek.clone(a); + + expect(b).to.equal(a); + expect(b.stack).to.equal(a.stack); + }); + + it('clones legacy extended Error with function property', () => { + + const CustomError = function () { + + Error.call(this); + }; + + Object.setPrototypeOf(CustomError.prototype, Error.prototype); + + const a = new CustomError('hello'); + a.fun = new Function(); + + const b = Hoek.clone(a); + + expect(b).to.equal(a); + expect(b.stack).to.equal(a.stack); + }); + it('cloned Error handles late stack update', () => { const a = new Error('bad');