BerriAI/litellm · error · HTTPException
ptu_effective_to must be after ptu_effective_from
Error message
ptu_effective_to must be after ptu_effective_from
What it means
Cross-field invariant guard on PTU model_info: the effective window has ptu_effective_to not strictly after ptu_effective_from. Checked before the count/rate gate because a patch touching only one window end carries no count/rate and would otherwise let an inverted window persist, where the next router load drops the deployment.
Source
Thrown at litellm/proxy/management_endpoints/model_management_endpoints.py:322
def _validate_ptu_model_info(model_info: Mapping[str, object]) -> None:
"""Enforce the PTU cross-field invariant on the effective model_info.
ptu_count and cost_per_ptu_per_hour must be set together, and a team_id and a
ptu_effective_from are required when they are. The start is mandatory rather than
defaulted because flat cost accrues from it: inferring one would let a deployment
configured today be billed for days it did not exist. Per-field bounds (positive
count, non-negative rate) are enforced by ModelInfo itself.
Window ordering is checked before the count/rate gate. A patch that touches only one
end of the window carries no count or rate, and ModelInfo sees one field at a time, so
leaving it to either would let an inverted window reach the row; the next load then
fails to parse it and drops the deployment out of the router, where no further patch
can repair it because each one re-parses the stored value first.
"""
effective_from: Final = _coerce_ptu_datetime(model_info.get("ptu_effective_from"))
effective_to: Final = _coerce_ptu_datetime(model_info.get("ptu_effective_to"))
if effective_from is not None and effective_to is not None and effective_to <= effective_from:
raise HTTPException(status_code=400, detail="ptu_effective_to must be after ptu_effective_from")
has_count: Final = model_info.get("ptu_count") is not None
has_rate: Final = model_info.get("cost_per_ptu_per_hour") is not None
if not has_count and not has_rate:
return
if has_count != has_rate:
raise HTTPException(status_code=400, detail="ptu_count and cost_per_ptu_per_hour must be set together")
if effective_from is None:
raise HTTPException(
status_code=400,
detail=(
"ptu_effective_from is required when PTU fields are set. Flat cost accrues from that "
"instant, so without it the start would have to be inferred and a deployment configured "
"today could be billed for days it did not exist"
),
)
if not model_info.get("team_id"):
raise HTTPException(View on GitHub (pinned to 77b7c6c40c)
Solutions
- Set ptu_effective_to to a timestamp later than ptu_effective_from.
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at litellm/proxy/management_endpoints/model_management_endpoints.py:322 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/e2ef1cd5f3edd93d.
Report an issue: GitHub.