Skip to content

[BUG] Description #24229

Description

@gempir

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists? --> I'm on the newest release and I didn't see any PRs related to this
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

PHP client generation produces invalid runtime validation for type: string, format: date-time properties when minLength or maxLength is present.

The PHP generator maps these properties to \DateTime, but still emits string length checks using mb_strlen(). During response deserialization, ObjectSerializer correctly converts the JSON string into a \DateTime. The generated model setter then receives that \DateTime and calls mb_strlen() on it, causing a runtime TypeError.

Actual runtime error:

mb_strlen(): Argument #1 ($string) must be of type string, DateTime given

Generated PHP snippet:

public function setStartsAt($starts_at)
{
    if (is_null($starts_at)) {
        throw new \InvalidArgumentException('non-nullable starts_at cannot be null');
    }
    if ((mb_strlen($starts_at) > 25)) {
        throw new \InvalidArgumentException('invalid length for $starts_at when calling ProductDealV1., must be smaller than or equal to 25.');
    }
    if ((mb_strlen($starts_at) < 20)) {
        throw new \InvalidArgumentException('invalid length for $starts_at when calling ProductDealV1., must be bigger than or equal to 20.');
    }

    $this->container['starts_at'] = $starts_at;

    return $this;
}

Same issue is generated in listInvalidProperties():

if ((mb_strlen($this->container['starts_at']) > 25)) {
    $invalidProperties[] = "invalid value for 'starts_at', the character length must be smaller than or equal to 25.";
}

if ((mb_strlen($this->container['starts_at']) < 20)) {
    $invalidProperties[] = "invalid value for 'starts_at', the character length must be bigger than or equal to 20.";
}

The serializer maps the value to \DateTime first:

if ($class === '\DateTime') {
    if (!empty($data)) {
        try {
            return new \DateTime($data);
        } catch (\Exception $exception) {
            return new \DateTime(self::sanitizeTimestamp($data));
        }
    } else {
        return null;
    }
}

Then hydration calls the generated setter with that \DateTime instance:

$propertyValue = $data->{$instance::attributeMap()[$property]};
$instance->$propertySetter(self::deserialize($propertyValue, $type, null));

Expected behavior:

The generated PHP client should deserialize valid date-time strings without throwing a TypeError.

Actual behavior:

The generated PHP client throws because mb_strlen() is called on a \DateTime.

openapi-generator version

Observed in generated PHP client with header:

Generator version: 7.24.0-SNAPSHOT

The same class of issue was previously observed for C# in older generator versions, where date / date-time fields mapped to DateTime or DateTimeOffset still received .Length checks.

OpenAPI declaration file content or url

Minimal reproduction:

openapi: 3.0.3
info:
  title: DateTime Length PHP Reproduction
  version: 1.0.0
paths:
  /deals:
    get:
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetDealsResponse'
components:
  schemas:
    GetDealsResponse:
      type: object
      required:
        - deals
      properties:
        deals:
          type: array
          items:
            $ref: '#/components/schemas/ProductDeal'
    ProductDeal:
      type: object
      required:
        - startsAt
      properties:
        startsAt:
          type: string
          format: date-time
          minLength: 20
          maxLength: 25
        endsAt:
          type: string
          format: date-time
          minLength: 20
          maxLength: 25

This produces PHP model mappings like:

protected static $openAPITypes = [
    'starts_at' => '\DateTime',
    'ends_at' => '\DateTime',
];

protected static $openAPIFormats = [
    'starts_at' => 'date-time',
    'ends_at' => 'date-time',
];

but also generates mb_strlen() checks for the same fields.

Generation Details

Generate a PHP client from the spec above.

Example:

openapi-generator-cli generate \
  -i openapi.yaml \
  -g php \
  -o generated-php-client

The issue occurs with normal generated response deserialization, for example through a generated endpoint method returning the model containing the date-time property.

Steps to reproduce
  1. Save the minimal OpenAPI spec above as openapi.yaml.
  2. Generate a PHP client:
openapi-generator-cli generate -i openapi.yaml -g php -o generated-php-client
  1. Use the generated client against a response like:
{
  "deals": [
    {
      "startsAt": "2024-01-01T00:00:00Z",
      "endsAt": "2099-01-01T00:00:00Z"
    }
  ]
}
  1. Let the generated client deserialize the response into the generated model.

Actual result:

mb_strlen(): Argument #1 ($string) must be of type string, DateTime given

Expected result:

The generated client should deserialize the response successfully into a model containing \DateTime values.

Related issues/PRs

Related discussion around minLength / maxLength on formatted string values:

This appears similar in shape to the C# generator issue where date / date-time fields mapped to DateTime or DateTimeOffset, but generated .Length validation.

Suggest a fix

For the PHP generator, do not emit mb_strlen() validation for properties generated as \DateTime.

Possible fixes:

  1. If type: string, format: date or format: date-time maps to \DateTime, skip minLength and maxLength validation in generated setters and listInvalidProperties().

  2. Alternatively, apply minLength / maxLength validation before deserializing the raw string into \DateTime.

  3. Or generate the property as string when string length constraints are present, although this would be a larger behavior change.

The core issue is that generated validation should match the generated PHP type. Once a schema property is generated as \DateTime, calling mb_strlen() on it is invalid and causes runtime failure for otherwise valid API responses.

Note: Some of this was LLM generated, but me, a human reviewed the entire output and the Problem.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions