Skip to content

fix: handle objects with broken toJSON in error annotation#3106

Open
mahmoodhamdi wants to merge 1 commit into
hapijs:masterfrom
mahmoodhamdi:fix/safe-stringify-toJSON-error
Open

fix: handle objects with broken toJSON in error annotation#3106
mahmoodhamdi wants to merge 1 commit into
hapijs:masterfrom
mahmoodhamdi:fix/safe-stringify-toJSON-error

Conversation

@mahmoodhamdi
Copy link
Copy Markdown
Contributor

When validating objects containing values with a toJSON method that throws (e.g. cloned URL instances on Node.js 20–22), Joi.assert() crashes with a TypeError instead of reporting the validation error.

Root cause

internals.safeStringify in annotate.js uses JSON.stringify with a custom replacer to handle circular references and special values. However, JSON.stringify calls toJSON() on values before the replacer can intervene. When @hapi/hoek's clone() produces a plain object that inherits a toJSON method requiring a specific receiver (like URL.prototype.toJSON), the call throws because this is no longer the correct instance.

Reproduction

const Joi = require('joi');

const schema = Joi.object({
    type: Joi.string().required(),
}).unknown(false);

Joi.assert(
    [{ someUrl: new URL('https://some-url.com') }],
    Joi.array().items(schema)
);
// Node.js 20-22: TypeError: Receiver must be an instance of class URL
// Expected: ValidationError with "[0].type" is required

Fix

Wrap JSON.stringify in safeStringify with a try-catch, falling back to a placeholder string. The validation error details are still reported in the error message.

Changes

  • lib/annotate.js: Added try-catch in safeStringify to handle broken toJSON methods
  • test/errors.js: Added test for objects with toJSON that throws

All tests pass: 1797 tests, 100% coverage, lint clean, types clean.

Closes #3070

When validating objects that contain values with a toJSON method that
throws (e.g. cloned URL instances on Node.js 20-22), Joi.assert()
crashes with a TypeError instead of reporting the validation error.

The safeStringify function now catches serialization errors and falls
back to a placeholder, allowing the validation error details to still
be reported.

Closes hapijs#3070
@Marsup
Copy link
Copy Markdown
Collaborator

Marsup commented Mar 30, 2026

Is there a real-world scenario where this is happening? It doesn't seem like it should be joi's responsibility to properly serialize something that unexpectedly fails.

@Marsup
Copy link
Copy Markdown
Collaborator

Marsup commented Mar 30, 2026

Sorry, just saw the original issue, I feel like the result of this fix is not as helpful as it could be on the annotation, as the fallback text just removes everything to replace it with that string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Problem serializing URL classes when stringifying a value

2 participants