Valid JSON can still be wrong

An assistant can produce valid JSON while inventing an order ID or returning a negative amount. Connecting model output to software requires a data contract: permitted fields, their types and acceptable values. Pydantic provides tools to define and validate that contract in Python. This guide concerns the boundary where untrusted output enters the application. A tidy response is not sufficient authorization to persist a record or trigger a business operation.

Separate structural validity from semantic validity. Structure checks fields and types. Semantics asks whether the referenced ticket exists, whether its current state permits the operation and whether the requester is authorized. A validation library addresses the first layer; trusted application data and business rules address the second. Our example validates a ticket summary with a positive identifier, limited priority values and a bounded title instead of saving arbitrary generated fields.

Define the output contract

Keep the contract small and use unambiguous names. Express a three-value priority as an enum-like literal rather than unconstrained text. Reject additional fields so typos and unexpected output do not disappear silently. Strict mode restricts implicit conversions for Python input, but JSON handling differs for some types. Test the exact ingestion path. The purpose is a predictable application boundary, not rejection for its own sake or the assumption that every provider supports the entire generated schema.

Turn validation failures into a useful, short explanation. Avoid recording private customer text or whole payloads in error logs. If a model may attempt one repair, return only the relevant contract error and cap retries. Repeated failure needs a defined manual path. Unbounded repair consumes resources and can disguise a fundamentally wrong answer as valid data. Track request ID, contract version and validation outcome to understand where failures originate.

Our suggested test set includes missing fields, wrong types, boundary values, overlong titles and unknown properties. Also test a perfectly conforming object with a nonexistent ticket ID; that case demonstrates the need for semantic checks. Evaluate generated results in a shadow workflow before enabling writes. Measure acceptance rate, field-specific failures and manual-review demand. Version contract changes like API changes so downstream consumers can adapt deliberately.

Code example and verification

This educational example demonstrates the implementation path. Check the stated runtime and prerequisites in a test environment; the notes explain what remains before production use.

Python with Pydantic 2; valid and invalid outputs
# python -m pip install "pydantic>=2,<3"
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field, ValidationError

class TicketSummary(BaseModel):
    model_config = ConfigDict(strict=True, extra="forbid")
    ticket_id: int = Field(gt=0)
    priority: Literal["low", "normal", "high"]
    title: str = Field(min_length=5, max_length=120)

valid = '{"ticket_id":42,"priority":"normal","title":"Delivery follow-up"}'
print(TicketSummary.model_validate_json(valid).model_dump())

invalid = '{"ticket_id":-1,"priority":"urgent","title":"x"}'
try:
    TicketSummary.model_validate_json(invalid)
except ValidationError as exc:
    # Do not log the original customer payload.
    print([(e["loc"], e["type"]) for e in exc.errors()])

The first object is accepted; the second produces identifier, priority and title-length errors. Generate JSON Schema with TicketSummary.model_json_schema(). This code does not establish that ticket 42 exists or that the user can modify it. Those checks belong between validation and persistence.

Make acceptance traceable

After schema acceptance, perform record existence, permission and state checks in the application service. Route writes through the normal controlled path rather than granting the model direct database access. Generated JSON Schema can support documentation and some model-provider configuration, but supported features differ. Success means fewer invalid objects cross the boundary and failures become visible. Factual correctness still requires independent evidence and review.

Implementation checklist

  • Install Pydantic 2 and version the contract.
  • Define types, lengths and ranges; reject unknown properties deliberately.
  • Separate schema errors from missing records and denied permissions.
  • Include a structurally valid but nonexistent record ID in acceptance tests.

Practical explanations and recommendations are Liyan Knowledge editorial analysis.Sources: Pydantic — Models · Pydantic — Strict mode · Pydantic — JSON Schema

This Liyan Knowledge article is an editorial synthesis based on the original source.View original source