joi icon indicating copy to clipboard operation
joi copied to clipboard

Custom error is ignored with multiply array items

Open 0pt1m1z3r opened this issue 1 year ago • 3 comments

Support plan

  • is this issue currently blocking your project? (yes/no): yes
  • is this issue affecting a production system? (yes/no): no

Context

  • node version: 14.19.0
  • module version with issue: 17.9.1, 17.9.2
  • last module version without issue:
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...):
  • any other relevant information:

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

Schema:

Joi.object({
    test: Joi.array().items(
        Joi.string(),
        Joi.number()
        .custom(function(value, helpers){
            if (value===5)
                return helpers.error('test_error');
            return value;
        })
        .messages({
            'test_error': 'Test error message',
        })
    ).single(),
})

Data To Validate:

{ 
  test: 5,
}

What was the result you got?

Validation Error: "test" does not match any of the allowed types

What result did you expect?

Validation Error: Test error message

0pt1m1z3r avatar May 03 '23 12:05 0pt1m1z3r

This is interesting. If you remove Joi.string(), you get the result you're looking for.

Joi.object({
  test: Joi.array()
    .items(
      Joi.number() //Removed Joi.string()
        .custom(function (value, helpers) {
          if (value === 5) return helpers.error('test_error');
          return value;
        })
        .messages({
          test_error: 'Test error message',
        }),
    )
    .single(),
});

//Returns 'Test error message'

If you instead return 6 instead of helpers.error('test_error'), it replaces it with 6 and passes validation.

Joi.object({
  test: Joi.array()
    .items(
      Joi.string(),
      Joi.number()
        .custom(function (value, helpers) {
          if (value === 5) return 6; //Replace error message with 6
          return value;
        })
        .messages({
          test_error: 'Test error message',
        }),
    )
    .single(),
});

//Passes validation, converts {test: 5} to {test: [6]}

waggonerjake avatar May 03 '23 20:05 waggonerjake

That's normal behavior, all possibilities will be attempted until a valid one is found, if none, there is no way to distinguish which one is the most likely, so this is the only rational error to provide.

Marsup avatar May 03 '23 20:05 Marsup

@Marsup at least the second one has custom handler and it could have priority. Moreover I got the correct result by wrapping "items" to alternatives(). Why it's not a problem for alternatives() to distinguish it?

Joi.object({
    test: Joi.array().items(Joi.alternatives(
        Joi.string(),
        Joi.number()
        .custom(function(value, helpers){
            if (value===5)
                return helpers.error('test_error');
            return value;
        })
        .messages({
            'test_error': 'Test error message',
        })
    )).single(),
})

0pt1m1z3r avatar May 03 '23 21:05 0pt1m1z3r