Skip to content

AbstractItemNormalizer::instantiateObject does not handle nullable constructor params without default #7837

@ddeboer

Description

@ddeboer

Description

AbstractItemNormalizer::instantiateObject throws MissingConstructorArgumentsException for nullable constructor parameters that don't have an explicit default value (= null), even when the parameter type allows null.

Symfony's base AbstractNormalizer::instantiateObject handles this case at line 390:

} elseif (!($context[self::REQUIRE_ALL_PROPERTIES] ?? $this->defaultContext[self::REQUIRE_ALL_PROPERTIES] ?? false) && $constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) {
    $params[$paramName] = null;
}

However, API Platform's AbstractItemNormalizer overrides instantiateObject and only checks isDefaultValueAvailable(), missing the nullable fallback:

} elseif ($constructorParameter->isDefaultValueAvailable()) {
    $params[] = $constructorParameter->getDefaultValue();
} else {
    // throws MissingConstructorArgumentsException or collects error
}

How to reproduce

Given a DTO/command class used as API Platform input:

final readonly class RequestActivity
{
    public function __construct(
        public ActivityId $activityId,
        public ?Timeslot $timeslot, // nullable, no default
    ) {}
}

Sending a POST request without the timeslot key in the JSON body results in:

MissingConstructorArgumentsException: Cannot create an instance of
"RequestActivity" from serialized data because its constructor requires
the following parameters to be present : "$timeslot".

Expected behaviour

The serializer should pass null for nullable constructor parameters when the data is missing, consistent with Symfony's AbstractNormalizer behaviour. The workaround is adding = null explicitly, but the serializer should respect ?Type without requiring it.

Versions

  • API Platform: 4.2.20
  • Symfony Serializer: 8.0.7
  • PHP: 8.3+

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