Skip to content

Joi.alternatives produces confusing message when used with nested object and { abortEarly: false } #2181

@CharlieEarnup

Description

@CharlieEarnup

Support plan

  • which support plan is this issue covered by? (e.g. Community, Core, Plus, or Enterprise):
  • is this issue currently blocking your project? (yes/no):
  • is this issue affecting a production system? (yes/no):

Context

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

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

Joi.alternatives produces wrong error when used with nested object and { abortEarly: false }

const schema = Joi.object().keys({
    foo: Joi.alternatives().try(
        Joi.string(),
        Joi.object().keys({
            bar: Joi.string(),
            baz: Joi.number(),
        })
    ),
});

// this will produce the correct error
const result1 = schema.validate({ foo: null }, { abortEarly: false });
console.log(JSON.stringify(result1.error, null, 2));
// this will produce an error which is wrong
const result2 = schema.validate({ foo: { bar: null, baz: null } }, { abortEarly: false });
console.log(JSON.stringify(result2.error, null, 2));

Normal .alternatives().try() message

{
  "_original": {
    "foo": null
  },
  "details": [
    {
      "message": "\"foo\" must be one of [string, object]",
      "path": [
        "foo"
      ],
      "type": "alternatives.types",
      "context": {
        "types": [
          "string",
          "object"
        ],
        "label": "foo",
        "value": null,
        "key": "foo"
      }
    }
  ]
}

output with confusing message

{
  "_original": {
    "foo": {
      "bar": null,
      "baz": null
    }
  },
  "details": [
    {
      "message": "\"foo\" does not match any of the allowed types",
      "path": [
        "foo"
      ],
      "type": "alternatives.match",
      "context": {
        "message": "\"foo\" must be a string. \"foo.bar\" must be a string. \"foo.baz\" must be a number",
        "details": [
          {
            "message": "\"foo\" must be a string",
            "path": [
              "foo"
            ],
            "type": "string.base",
            "context": {
              "label": "foo",
              "value": {
                "bar": null,
                "baz": null
              },
              "key": "foo"
            }
          },
          {
            "message": "\"foo.bar\" must be a string",
            "path": [
              "foo",
              "bar"
            ],
            "type": "string.base",
            "context": {
              "label": "foo.bar",
              "value": null,
              "key": "bar"
            }
          },
          {
            "message": "\"foo.baz\" must be a number",
            "path": [
              "foo",
              "baz"
            ],
            "type": "number.base",
            "context": {
              "label": "foo.baz",
              "value": null,
              "key": "baz"
            }
          }
        ],
        "label": "foo",
        "value": {
          "bar": null,
          "baz": null
        },
        "key": "foo"
      }
    }
  ]
}

What was the result you got?

"\"foo\" must be a string" as the message
"string.base" type

What result did you expect?

"\"foo\" must be one of [string, object]" as the message
"alternatives.types" type

Metadata

Metadata

Assignees

Labels

non issueIssue is not a problem or requires changes

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions