Skip to content

object|<Class> docblocks in DispatchTrait break metadata warmup under symfony/type-info 7.4 (Cannot create union with both "object" and class type) #8312

Closed

Description

@schmunk42

API Platform version

4.3.13

PHP version

8.4

Description

api-platform/core 4.3 ships redundant union docblocks of the form
object|<Class> in its own source:

  • src/Symfony/Messenger/DispatchTrait.php:28 → @param object|Envelope $message
  • src/Doctrine/Common/Messenger/DispatchTrait.php:28 → @param object|Envelope $message

With symfony/type-info 7.4 installed, the PhpStanExtractor that API Platform
wires as api_platform.property_info.php_stan_extractor throws an Exception while building
the type graph whenever it parses such a docblock:

Symfony\Component\TypeInfo\Exception\InvalidArgumentException:
Cannot create union with both "object" and class type.
  at vendor/symfony/type-info/Type/UnionType.php:75

object|Envelope is redundant — object already subsumes every class type.
The legacy symfony/property-info Type model tolerated this; symfony/type-info
7.4 rejects it hard.

This regressed cache:clear / routing warmup on the Symfony 7.3 → 7.4 bump.

Relation to #8201 / #8206

PR #8206 (released in 4.3.10) isolated the framework property_info service
from API Platform's extractors via private api_platform.property_info.* tags +
a bridge compiler pass. That fixed the path where API Platform's PhpStanExtractor
leaked into the framework service (Sylius @template T of object crash).

It does not cover this case: API Platform's own PhpStanExtractor still
parses object|<Class> docblocks during metadata warmup and hits the same
type-info exception. The remaining 4.3 path is still affected.

How to reproduce

Minimal standalone reproduction (public packages only, no app kernel needed):
https://gist.github.com/schmunk42/3357f3d0fdffe11e977812900355cefd

composer install
php repro.php
PHP            : 8.4.22
api-platform/core: v4.3.13
symfony/type-info: v7.4.9
symfony/property-info: v7.4.8
------------------------------------------------------------
[KO]  Symfony\Component\TypeInfo\Exception\InvalidArgumentException: Cannot create union with both "object" and class type.
      thrown from: .../symfony/type-info/Type/UnionType.php:75

The gist invokes the exact extractor API Platform wires as
api_platform.property_info.php_stan_extractor directly
Title:


on a property whose
docblock mirrors the DispatchTrait shape (@var object|Envelope).

You can also confirm the offending docblocks directly:

grep -rn "object|Envelope" vendor/api-platform/core/src
# src/Doctrine/Common/Messenger/DispatchTrait.php:28
# src/Symfony/Messenger/DispatchTrait.php:28

Possible solution

Drop the redundant |Envelope from both DispatchTrait docblocks — the
method already declares object $message / : Envelope in the signature, so
the docblock carries no extra information:

-    /**
-     * @param object|Envelope $message
-     */
     private function dispatch(object $message): Envelope

(or @param object $message if a docblock is desired). This keeps the source
free of redundant unions that symfony/type-info 7.4 rejects.

Activity

  1. github-actions commented on Aug 16, 2026

    @github-actions

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  2. schmunk42 commented on Aug 16, 2026

    @schmunk42
    Author

    This is still an issue and others are also affected by this, please let me know if I should provide additional information or create a PR.

  3. schmunk42 commented on Sep 22, 2026

    @schmunk42
    Author

    Fixed by #8410 (0864f2f), first released in v4.3.18. Verified on v4.4.0: both src/Symfony/Messenger/DispatchTrait.php and src/Doctrine/Common/Messenger/DispatchTrait.php no longer carry the @param object|Envelope docblock, and cache:clear --env=prod warms up cleanly again. Thanks @ousamabenyounes!

    One note for anyone landing here with the same error message after upgrading to Symfony 7.4 — the api-platform docblocks were not the only source. symfony/type-info also resolves @template bounds (TypeContext\TypeContextFactory::collectTemplates()), and that path is reached through api-platform's own property metadata:

    ApiPlatform\Metadata\Resource\Factory\UriTemplateResourceMetadataCollectionFactory
      → LinkFactory::getIdentifiersFromResourceClass()
      → ApiPlatform\Metadata\Property\Factory\PropertyInfoPropertyMetadataFactory
      → Symfony ConstructorExtractor → PhpStanExtractor::getTypeFromConstructor()
      → TypeContextFactory::collectTemplates()  → Type::union() → InvalidArgumentException
    

    In our stack the remaining offender is gedmo/doctrine-extensions, which declares @phpstan-template T of Loggable|object on AbstractLogEntry (also LogEntryRepository and LoggableListener) — tracked at doctrine-extensions/DoctrineExtensions#3044 with an open PR doctrine-extensions/DoctrineExtensions#3046. Same exception, different library, so the symptom is easy to mistake for this issue still being unfixed.

    Closing this as resolved.

  4. schmunk42 commented on Sep 22, 2026

    @schmunk42
    Author

    Correction to my comment above, so the record is precise: the DispatchTrait docblocks are indeed gone as of v4.4.0 — that part is verified. But our cache:clear --env=prod only warms up cleanly because we still neutralise Symfony's property_info.phpstan_extractor on our side. With the real PhpStanExtractor active on api-platform 4.4.0 / symfony 7.4.19 / type-info 7.4.17, warmup still aborts — on the gedmo @phpstan-template T of Loggable|object bounds described above, not on anything in api-platform. So this issue is correctly closed; the remaining failure belongs to doctrine-extensions/DoctrineExtensions#3044.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    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