#10195·dspy

[Bug] JSONAdapter structured outputs: pydantic Field constraints (ge, le, multiple_of, pattern) are silently dropped in the signature-to-model derivation — is this intentional?

Author: arjmandiCreated Aug 11, 2026Updated Sep 5, 2026

What happens

Field-level constraint kwargs on OutputField never reach any structured-output backend — the derived response-format model keeps the type but drops the constraint metadata:

python
import dspy
from dspy.adapters.json_adapter import _get_structured_outputs_response_format

class Score(dspy.Signature):
    text: str = dspy.InputField()
    score: float = dspy.OutputField(ge=0.0, le=1.0, multiple_of=0.25)

print(_get_structured_outputs_response_format(Score, True).model_json_schema())
# {'properties': {'score': {'title': 'Score', 'type': 'number'}}, ...}
# ge / le / multipleOf: gone

Constraints expressed in the annotation itself survive (Literal[...], nested models, set[str] -> uniqueItems); constraints passed as Field kwargs do not. Users writing OutputField(ge=0, le=1) reasonably believe the bound is part of the contract; outputs violating it parse fine and flow downstream. dspy 3.2.1, Python 3.12.

The question

Is the stripping intentional? A plausible reason would be provider compatibility: OpenAI's strict structured outputs REJECT schemas containing unsupported keywords like multipleOf, so passing constraints through naively would break those calls. But today's behavior drops them for every backend equally — including local/vLLM grammar backends that could enforce some of them, and validation layers that could at least check them (related territory: #7925 on partial output-field validation).

If intentional, a suggestion

Strip per-provider rather than globally — or pass constraints through and let each backend declare what it can't honor. #9686 shows the same schema-hygiene problem in the opposite direction (vendor extensions leaking TO strict providers), so a single provider-aware schema-sanitization point might solve both.

Happy to work on a PR for whichever direction maintainers prefer. We hit this while integrating a grammar backend and wrote up the full analysis with workarounds here: https://www.evolutionid.com/en/technical-insights/your-dspy-field-constraints-never-reach-the-model.