Skip to content

Fix match('one') reporting any when exclusive object alternatives overlap - #3159

Open
SahinurDEV wants to merge 1 commit into
hapijs:masterfrom
SahinurDEV:fix/alternatives-match-one-overlap
Open

SahinurDEV wants to merge 1 commit into
hapijs:masterfrom
SahinurDEV:fix/alternatives-match-one-overlap

Conversation

@SahinurDEV

Copy link
Copy Markdown

Fixes #3058.

Problem

alternatives().match('one') already reports alternatives.one when more than one alternative validates successfully. Exclusive object alternatives such as { a } vs { b } plus shared keys do not take that path: each object fails only because the other alternative's keys are unknown, so Joi previously reported alternatives.any ("does not match any of the allowed types").

That is the opposite of what happened — both schemas would match if the sibling exclusive keys were ignored — so callers cannot tell a true "no match" from a "more than one matched" exclusivity violation.

Fix

When match('one') finds zero successful matches, check whether the failures are explained only by keys declared on sibling alternatives. Strip those sibling keys and revalidate each candidate. If more than one then matches, report alternatives.one instead of alternatives.any.

Revalidation is required because abortEarly can hide later object rules (for example .and()) behind an object.unknown error.

Single-alternative matches, shared-only values that already take the multi-match path, unrelated unknown keys, and real field errors (invalid email, etc.) are unchanged.

Tests

Added regression coverage for:

npm test — 1841 tests, 100% coverage, lint and types clean.

…rlap

When alternatives().match('one') uses exclusive object schemas (e.g. { a }
vs { b } plus shared keys), each alternative fails only because the other
alternative's keys are unknown. That left matched.length at 0, so Joi
reported alternatives.any instead of alternatives.one.

When failed alternatives only differ by keys declared on sibling
alternatives, strip those sibling keys and revalidate. If more than one
then matches, report alternatives.one. Revalidation is required because
abortEarly can hide later object rules (for example .and()) behind an
object.unknown error.

Fixes hapijs#3058
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.

alternatives().match("one") incorrectly reports that there's no match, when the error is that all schemas match

1 participant