Skip to content

[BUG CLIENT]: JSONSchema Serialization Inconsistency with Alias Field #310

@tiborrr

Description

@tiborrr

Python -VV

Python 3.13.7 (main, Sep 25 2025, 21:20:20) [Clang 17.0.0 (clang-1700.3.19.1)]

Pip Freeze

aiofiles==25.1.0
alembic==1.17.2
annotated-doc==0.0.4
annotated-types==0.7.0
anyio==4.11.0
appdirs==1.4.4
APScheduler==3.11.1
argon2-cffi==25.1.0
argon2-cffi-bindings==25.1.0
async-property==0.2.2
certifi==2025.8.3
cffi==2.0.0
charset-normalizer==3.4.3
click==8.3.0
cryptography==46.0.1
debugpy==1.8.19
Deprecated==1.2.18
deprecation==2.1.0
distro==1.9.0
dnspython==2.8.0
ecdsa==0.19.1
elementpath==5.0.4
email-validator==2.3.0
eval_type_backport==0.2.2
fastapi==0.121.3
frozendict==2.4.6
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.10
img2pdf==0.6.1
iniconfig==2.3.0
invoke==2.2.1
Jinja2==3.1.6
jwcrypto==1.5.6
lxml==6.0.2
Mako==1.3.10
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mdurl==0.1.2
minio==7.2.18
mistralai==1.9.11
mollie-api-python==3.9.1
oauthlib==3.3.1
ocrmypdf==16.11.0
packaging==25.0
pdfminer.six==20250506
pi_heif==1.1.0
pikepdf==9.11.0
pillow==11.3.0
pluggy==1.6.0
pyasn1==0.6.1
pycparser==2.23
pycryptodome==3.23.0
pydantic==2.11.10
pydantic-settings==2.12.0
pydantic-xml==2.18.0
pydantic_core==2.33.2
Pygments==2.19.2
pyschematron==1.1.13
pytest==9.0.1
pytest-asyncio==1.3.0
python-dateutil==2.9.0.post0
python-dotenv==1.2.1
python-jose==3.5.0
python-keycloak==5.8.1
python-multipart==0.0.20
PyYAML==6.0.3
requests==2.32.5
requests-oauthlib==2.0.0
requests-toolbelt==1.0.0
rich==14.1.0
rsa==4.9.1
ruyaml==0.91.0
setuptools==80.9.0
shellingham==1.5.4
six==1.17.0
sniffio==1.3.1
SQLAlchemy==2.0.43
sqlmodel==0.0.27
starlette==0.48.0
typer==0.19.2
typing-inspection==0.4.2
typing_extensions==4.15.0
tzlocal==5.3.1
urllib3==2.5.0
uvicorn==0.38.0
wrapt==1.17.3
xmlschema==4.1.0

Reproduction Steps

  1. Create a simple Pydantic model:
from mistralai.extra import response_format_from_pydantic_model
from pydantic import BaseModel, Field
import json

class TestModel(BaseModel):
    name: str = Field(description="A name field")
    value: int = Field(description="A value field")
  1. Generate a ResponseFormat using the SDK function:
response_format = response_format_from_pydantic_model(TestModel)
  1. Serialize using model_dump() without by_alias=True:
serialized = response_format.model_dump(mode='json')
print(json.dumps(serialized, indent=2))
  1. Observe that json_schema.schema is null instead of containing the schema definition.

  2. Compare with model_dump(by_alias=True):

serialized_with_alias = response_format.model_dump(mode='json', by_alias=True)
print(json.dumps(serialized_with_alias, indent=2))

Expected Behavior

hen calling model_dump() on a ResponseFormat object created with response_format_from_pydantic_model(), the json_schema.schema field should contain the actual JSON schema definition, not null. The serialization should work consistently regardless of whether by_alias=True is used.

The expected output should be:

{
  "type": "json_schema",
  "json_schema": {
    "name": "TestModel",
    "schema": {
      "type": "object",
      "properties": {
        "name": {"type": "string", "description": "A name field"},
        "value": {"type": "integer", "description": "A value field"}
      },
      "required": ["name", "value"],
      "additionalProperties": false
    },
    "strict": true
  }
}

Additional Context

Current Behavior:

  • model_dump() shows schema: null
  • model_dump(by_alias=True) correctly shows the schema
  • Actual API calls succeed because the SDK's marshal_json() function (used for HTTP requests) internally calls model_dump(by_alias=True)

Root Cause:
The issue is in JSONSchema.model_serializer (located in mistralai/models/jsonschema.py). The serializer attempts to retrieve the schema_definition field using its alias "schema", but handler(self) returns a dict with the field name "schema_definition" instead of the alias when by_alias=False:

@model_serializer(mode="wrap")
def serialize_model(self, handler):
    serialized = handler(self)  # Returns {"schema_definition": {...}, ...}
    
    for n, f in type(self).model_fields.items():
        k = f.alias or n  # k = "schema" (alias)
        val = serialized.get(k)  # Returns None because key is "schema_definition", not "schema"

Impact:
While API calls work, this inconsistency causes confusion for:

  • Debugging/inspecting serialized data
  • Logging request payloads
  • Testing code that relies on model_dump()
  • Potential breakage if HTTP serialization method changes

Suggested Solutions

Suggested Fix:
The JSONSchema.model_serializer should check for both the alias key and the field name:

@model_serializer(mode="wrap")
def serialize_model(self, handler):
    serialized = handler(self)
    
    for n, f in type(self).model_fields.items():
        k = f.alias or n
        # Try alias first, then field name as fallback
        val = serialized.get(k) or serialized.get(n)
        # ... rest of logic ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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