Claus Ibsen created CAMEL-25238:
-----------------------------------
Summary: camel-yaml-dsl-validator - a oneOf used twice in one file
picks one winner for both, so the second place is asked for a property it does
not need
Key: CAMEL-25238
URL: https://issues.apache.org/jira/browse/CAMEL-25238
Project: Camel
Issue Type: Bug
Components: camel-core
Reporter: Claus Ibsen
A {{oneOf}} or {{anyOf}} that appears twice in one file, with a different
branch being the intended one each time, makes the validator report that the
second place needs a property it does not. Minimal reproducer -- no Kamelet
involved:
{code:yaml}
- route:
id: r
from:
uri: timer:t
steps:
- choice:
when:
- simple: "${header.x} == 'JSON'"
steps:
- unmarshal:
fhirJson:
fhirVersion: "{{fhirVersion}}"
- simple: "${header.x} == 'XML'"
steps:
- unmarshal:
fhirXml:
fhirVersion: "{{fhirVersion}}"
{code}
{noformat}
Line 16: /0/route/from/steps/0/choice/when/1/steps/0/unmarshal: required
property 'fhirJson' not found
{noformat}
The file is correct: {{fhirXml}} is a data format of {{unmarshal}} and
{{fhirVersion}} is a property placeholder, which the runtime resolves before it
looks at the value. {{fhir-sink.kamelet.yaml}} of camel-kamelets has exactly
this shape, which is where it was found.
h3. What triggers it
Each of these alone is fine; all three together are not:
|| variant || errors ||
| fhirJson {{{{ph}}}} + fhirXml {{{{ph}}}} | *1* |
| the same with a literal R4 instead of the placeholder | 0 |
| fhirXml {{{{ph}}}} twice (the same data format in both branches) | 0 |
| json/Jackson + fhirXml {{{{ph}}}} (one branch without errors), either order |
0 |
| fhirXml {{{{ph}}}} in one branch alone | 0 |
So it needs two places under the same {{anyOf}}, *both* producing errors, with
a *different* branch being the intended one in each.
h3. Why
{{YamlValidator.filterOneOfNoise}} exists because a {{oneOf}} whose branches
all fail reports the errors of every branch, which is dozens of "required
property X not found" for branches nobody wrote. It groups the errors by the
branch of the schema they came from, picks the branch that matched the YAML
most closely, and drops the rest.
It groups by the *evaluation* path, which is the path through the schema. Two
places in a file validated against the same {{anyOf}} have the same evaluation
path and different instance locations, so their errors are pooled and *one*
winner is chosen for both. In the reproducer the fhirJson branch wins on the
strength of the error at {{when/0}}, so at {{when/1}} the fhirXml branch's
error is dropped as a loser and fhirJson's "required" error is kept -- at a
place that never mentioned fhirJson.
h3. The obvious fix regresses the documentation corpus
Grouping by instance location as well as by branch, so each place picks its own
winner, fixes the reproducer and all five variants. It also makes
{{YamlRoundTripTest}} and three others fail: about twenty examples from the
Camel documentation (loop, throttle, split, wireTap, rollback, routingSlip,
oncompletion, rest-dsl, error-handler, openai-responses) start reporting
"object found, string expected (constant is a plain string: write constant:
"...", not a language map)".
Those examples are valid, so the global pooling is load-bearing: a place whose
own best branch is a type error is currently rescued by another place that
chose a property-level branch. Splitting the groups removes that rescue. So the
fix wants the tiering reconsidered together with those cases, not a one-line
change, and the corpus in {{camel-yaml-dsl-validator}} is the gate for it.
Found while validating the 250 kamelets of camel-kamelets against the schema
for CAMEL-25194. After that one, 249 of 250 validate clean and this is the only
report left.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)