From eabb1e12d3f1aadc81b8f6107fe5865ff0dedbe1 Mon Sep 17 00:00:00 2001 From: Gil Pedersen Date: Thu, 14 Nov 2024 16:15:29 +0100 Subject: [PATCH] Fix cloning Util.inherit() subclassed errors. Backports #401 --- lib/clone.js | 8 +++++--- test/clone.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) 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');