Bug Report Checklist
Description
The Python generator emits Pydantic v2 regex validators without specifying mode="before":
@field_validator("created_at")
def created_at_validate_regular_expression(cls, value):
if not isinstance(value, str):
value = str(value)
if not re.match(PATTERN, value):
raise ValueError(...)
return value
Pydantic field validators default to mode="after". Consequently, formatted OpenAPI strings have already been converted to their Python types before the regex runs.
For a string with format: date-time, the validator receives a datetime. Converting it with str(value) produces something such as:
2026-05-29 06:25:09.281000+00:00
This cannot match a pattern expecting the original RFC 3339 representation:
Therefore, a valid API response is rejected.
The same template also affects types such as UUID: the after validator receives a UUID, converts it to str, and returns the string. The resulting model field can therefore contain a str despite
being annotated as UUID.
The relevant template is:
modules/openapi-generator/src/main/resources/python/model_generic.mustache
openapi-generator version
Latest master. The current Python model_generic.mustache still generates regex validators without mode="before".
OpenAPI declaration file content or url
openapi: 3.0.3
info:
title: Regex validation reproduction
version: 1.0.0
paths: {}
components:
schemas:
Example:
type: object
required:
- id
- createdAt
properties:
id:
type: string
format: uuid
pattern: '^[0-9a-fA-F-]{36}$'
createdAt:
type: string
format: date-time
pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$'
Generation Details
openapi-generator-cli generate \
-g python \
-i openapi.yaml \
-o generated-client
Steps to reproduce
from uuid import UUID
from openapi_client.models.example import Example
model = Example.model_validate(
{
"id": "0190d9f0-ab12-7000-8000-abc123456789",
"createdAt": "2026-05-29T06:25:09.281Z",
}
)
assert isinstance(model.id, UUID)
Actual behavior
createdAt is parsed into a datetime before the regex validator executes. The validator converts that value using str(datetime_value), and the resulting value does not match the OpenAPI pattern.
Model validation fails.
For UUID fields with patterns, the validator returns str(value), potentially changing the field from UUID back to str.
Expected behavior
OpenAPI pattern applies to the string representation supplied on the wire. The regex should therefore be evaluated before Pydantic converts formatted strings into Python types.
After validation:
- A valid RFC 3339 string should be accepted and stored as a
datetime.
- A valid UUID string should be accepted and stored as a
UUID.
- Strings that do not match the declared pattern should be rejected.
- Already-typed Python values should not be unexpectedly converted to strings.
Related issues/PRs
Suggest a fix
Regex validators should use mode="before":
@field_validator("created_at", mode="before")
@classmethod
def created_at_validate_regular_expression(cls, value):
if isinstance(value, str) and not re.match(PATTERN, value):
raise ValueError("must validate the regular expression")
return value
Returning the original value allows Pydantic to perform the subsequent conversion to datetime, UUID, or another declared Python type.
This change should apply to generated regex validators. Enum validators inspect already-parsed values and do not necessarily need to change.
Bug Report Checklist
Description
The Python generator emits Pydantic v2 regex validators without specifying
mode="before":Pydantic field validators default to
mode="after". Consequently, formatted OpenAPI strings have already been converted to their Python types before the regex runs.For a
stringwithformat: date-time, the validator receives adatetime. Converting it withstr(value)produces something such as:This cannot match a pattern expecting the original RFC 3339 representation:
Therefore, a valid API response is rejected.
The same template also affects types such as
UUID: the after validator receives aUUID, converts it tostr, and returns the string. The resulting model field can therefore contain astrdespitebeing annotated as
UUID.The relevant template is:
openapi-generator version
Latest
master. The current Pythonmodel_generic.mustachestill generates regex validators withoutmode="before".OpenAPI declaration file content or url
Generation Details
Steps to reproduce
Actual behavior
createdAtis parsed into adatetimebefore the regex validator executes. The validator converts that value usingstr(datetime_value), and the resulting value does not match the OpenAPI pattern.Model validation fails.
For UUID fields with patterns, the validator returns
str(value), potentially changing the field fromUUIDback tostr.Expected behavior
OpenAPI
patternapplies to the string representation supplied on the wire. The regex should therefore be evaluated before Pydantic converts formatted strings into Python types.After validation:
datetime.UUID.Related issues/PRs
Suggest a fix
Regex validators should use
mode="before":Returning the original value allows Pydantic to perform the subsequent conversion to
datetime,UUID, or another declared Python type.This change should apply to generated regex validators. Enum validators inspect already-parsed values and do not necessarily need to change.