Skip to content

fix(serializer): preserve deserialization path and expected type on IRI type-confusion guard#8353

Merged
soyuka merged 2 commits into
api-platform:4.3from
alexndlm:fix/iri-type-confusion-violation-path
Jun 26, 2026
Merged

fix(serializer): preserve deserialization path and expected type on IRI type-confusion guard#8353
soyuka merged 2 commits into
api-platform:4.3from
alexndlm:fix/iri-type-confusion-violation-path

Conversation

@alexndlm

Copy link
Copy Markdown
Contributor
Q A
Branch? 4.3
Tickets Closes #8352
License MIT

Problem

The type-confusion guard in AbstractItemNormalizer::getResourceFromIri() throws a bare NotNormalizableValueException, which carries neither the deserialization path nor the expected type:

if (!$matchesType) {
    throw new NotNormalizableValueException(\sprintf('The iri "%s" does not reference the correct resource.', $data));
}

When COLLECT_DENORMALIZATION_ERRORS is enabled (the default for DeserializeProvider), DeserializeProvider::createViolationFromException() then builds a ConstraintViolation with an empty property path and an empty expected type, so the user-facing violation degrades to This value should be of type . with no property name.

Before #8333 the guard threw an InvalidArgumentException, which was caught a few lines below and re-thrown via NotNormalizableValueException::createForUnexpectedDataType(...) — preserving both the path and the expected type. #8333 changed the throw to a NotNormalizableValueException (so union/intersection denormalization can fall through to the next member) but stopped going through the factory, dropping that metadata for the single-type case. This is a regression vs 4.3.13.

POST a valid IRI that points to a resource of the wrong type for a relation:

POST /books
{ "title": "t", "printingHouse": "/publishing-houses/1" }
  • 4.3.13: propertyPath: "printingHouse", Invalid IRI "/publishing-houses/1".
  • 4.3.14: propertyPath: "", This value should be of type .

Fix

Keep the exception a NotNormalizableValueException (so the union/intersection fallback from #8333 / #8339 still works), but build it through createForUnexpectedDataType() so the deserialization path and expected type are preserved on the resulting violation.

Tests

Note: the functional harness wouldn't boot in my local sandbox (kernel warmup fails on an unrelated mcp config in the fixture app). The unit test covers the precise denormalization path; CI validates the functional suite.

…RI type-confusion guard

The type-confusion guard in AbstractItemNormalizer::getResourceFromIri()
threw a bare NotNormalizableValueException, dropping the deserialization
path and expected type. With COLLECT_DENORMALIZATION_ERRORS enabled,
DeserializeProvider::createViolationFromException() then produced an empty
"This value should be of type ." violation with no property path
(regression from api-platform#8333 vs 4.3.13).

Build the exception through createForUnexpectedDataType() so the path and
expected type are preserved, while keeping it a NotNormalizableValueException
so union/intersection denormalization still falls through to the next member.

Closes api-platform#8352

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2715c78704

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/Serializer/AbstractItemNormalizer.php Outdated
…guard

For a union/intersection relation the guard now derives the expected types
from the declared relation type (context['relation_native_type']) instead of
reporting only the single class currently being attempted, so the restored
validation metadata is accurate for union relations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alexndlm

Copy link
Copy Markdown
Contributor Author

Heads-up on CI: the failing jobs (PHPUnit (PHP 8.3) (Symfony lowest), PHPUnit api-platform/serializer (PHP 8.5 lowest)) are pre-existing on 4.3, not introduced here. On the base commit (be26bbe) the same single failure is present:

  • UnionIriCollectionTest::testDenormalizeCollectionAcceptsIriOfEachUnionMember (added in fix(serializer): accept union-typed IRI collections on denormalization #8339) — Tests: 1957 … Failures: 1, identical on base and on this branch.
  • AbstractItemNormalizerTest::testUnionTypeCollectionDenormalizationAcceptsAnyMember — base Tests: 105 … Errors: 1, this branch Tests: 106 … Errors: 1 (the extra test is the new passing one here).

On symfony/property-info lowest, context['relation_native_type'] is a legacy type rather than a TypeInfo\Type, so the union-collection guard falls back to is_a() against the first member and rejects a valid IRI for the second one. That is a pre-existing #8339 gap on the lowest stack, unrelated to this regression fix — this PR only changes the message text of that already-failing assertion (does not reference the correct resource.Invalid IRI "…".). Happy to open a separate PR for the lowest-stack union-collection case if useful.

@soyuka soyuka merged commit 37dfcb3 into api-platform:4.3 Jun 26, 2026
108 of 112 checks passed
@soyuka

soyuka commented Jun 26, 2026

Copy link
Copy Markdown
Member

Thanks!

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.

2 participants