⚠ This page is served via a proxy. Original site: https://github.com
This service does not collect credentials or authentication data.
Skip to content

Bug: ItemNormalizer intercepting DateTimeImmutable before DateTimeNormalizer due to priority conflict #7733

@vincent-philippe

Description

@vincent-philippe

API Platform version(s) affected: 4.2.11

Description There is a priority conflict within the Serializer chain where ApiPlatform\Serializer\ItemNormalizer (and its JSON-LD counterpart) intercepts DateTimeImmutable objects before Symfony's native DateTimeNormalizer can handle them.

When a custom normalizer or a specific serialization flow delegates the normalization of a property containing a DateTimeImmutable to the main Serializer, the ItemNormalizer (positioned higher in the priority list) attempts to treat the date as an API resource. It fails while trying to find an identifier (e.g., id), throwing a LogicException.

How to reproduce 1. Define a custom normalizer that delegates work to the global Serializer:

public function normalize(mixed $data, ?string $format = null, array $context = []): array
{
    $normalize = [];
    if ($data->updatedAt) {
        // updatedAt is a DateTimeImmutable
        // This call will trigger the ItemNormalizer instead of DateTimeNormalizer
        $normalize['updatedAt'] = $this->serializer->normalize($data->updatedAt, $format, $context);
    }

    // ... base normalization logic ...
    
    return $normalize;
}
Observe the normalizer order in the compiled container :
        ...

        ApiPlatform\JsonLd\Serializer\ItemNormalizer (Position 18)

        ApiPlatform\Serializer\ItemNormalizer (Position 19)

        Symfony\Component\Serializer\Normalizer\DateTimeNormalizer (Position 20)

        ...

The execution fails with the following error: LogicException: Can't get a way to read the property "id" in class "DateTimeImmutable".

Possible Solution

The DateTimeNormalizer (and other specialized Symfony normalizers like UidNormalizer) should have a higher priority than ItemNormalizer. Currently, ItemNormalizer acts as a "greedy" catch-all for any object that is not explicitly handled by a previous specialized normalizer.

Lowering the priority of ItemNormalizer would ensure dates are formatted before the system tries to resolve them as API resources.

...

ApiPlatform\JsonLd\Serializer\ItemNormalizer (Position 18)

ApiPlatform\Serializer\ItemNormalizer (Position 19)

Symfony\Component\Serializer\Normalizer\DateTimeNormalizer (Position 20 - Too low!)

...

Symfony\Component\Serializer\Normalizer\ObjectNormalizer (Position 33)

Because the custom normalizer calls the global Serializer for a date, the Serializer starts searching from the top of the list and matches the ItemNormalizer at Position 18/19 because it is a class, before reaching the correct specialist at Position 20.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions