hapijs / joi

The most powerful data validation library for JS
Other
20.95k stars 1.51k forks source link

Calls to `annotate()` fail with TypeError when using `.when` or `.conditional` #3048

Closed CynicalBusiness closed 3 months ago

CynicalBusiness commented 3 months ago

Runtime

Node.js

Runtime version

20.10.0

Module version

17.13.3

Last module version without issue

No response

Used with

NestJS, but being validated manually in this case

Any other relevant information

This can be replicated in the sandbox:

Schema:

Joi.object({
    strategy: Joi.string().valid("strategyA", "strategyB").default("strategyA"),
    strategyA: Joi.when("strategy", {
        is: "strategyA",
        then: Joi.object({
            client: Joi.object({
                key: Joi.string().required(),
            }).default(),
        }).default(),
    }),
}).default()

Data:

{}

I have tried a few different combinations of .when() and/or conditional() but the same problem appears.

What are you trying to achieve or the steps to reproduce?

I am attempting to call .annotate() on the resulting validation error.

What was the result you got?

Error was thrown from within Joi:

TypeError: Cannot read properties of undefined (reading 'client')
      at exports.ValidationError.exports.error [as annotate] (${workspaceRoot}/node_modules/joi/lib/annotate.js:40:28)
      at InstanceWrapper.metatype (${workspaceRoot}/packages/core/src/config.ts:95:65) // this is my code
      ... // the rest is my code and/or framework

What result did you expect?

An annotated string is generated.

Marsup commented 3 months ago

Are you using it in the frontend? Cause I can't reproduce in node, but there indeed seems to be an issue with the sandbox.

Edit: I forgot to call annotate, now I see the problem 🤦🏻‍♂️

CynicalBusiness commented 3 months ago

I was playing around in the sandbox some more, and, it does not look like it is annotate's fault at all. In fact, the schema I gave is just generally invalid, even without the .when (where the object is specified directly).

It seems to be the fault of those .default() calls on the objects. Something about a .required() key being inside an object with default() sets it off.

Marsup commented 3 months ago

Joi should probably not error like that, but in the meantime, your schema is wrong. You can't both ask to create a default object and require a property in it that you don't provide.

CynicalBusiness commented 3 months ago

Joi should probably not error like that, but in the meantime, your schema is wrong. You can't both ask to create a default object and require a property in it that you don't provide.

Yep, that looks like it. I just kept managing to trigger it in a strange way.

Changing the .default() calls for .required() makes the error go away and schema validate as expected.

Marsup commented 3 months ago

I see we reached the same conclusion, you're indeed responsible for making valid defaults, all .default() (without args) does is use an empty object and apply inner defaults, but if your schema requires some properties or your default value is invalid with the inner schema, it will indeed fail.