Significant-Gravitas/AutoGPT · warning · HTTPException
`since` must be earlier than or equal to `until`.
Error message
`since` must be earlier than or equal to `until`.
What it means
Raised (422) by GET /usage/execution_costs (user cost summary) when both since and until query params are provided and since > until. The endpoint aggregates a time window; an inverted window is nonsensical and rejected before querying. top_runs_limit is separately constrained to [1,50] by Query(ge/le) metadata.
Source
Thrown at autogpt_platform/backend/backend/api/features/v1.py:2124
user_id: Annotated[str, Security(get_user_id)],
since: datetime | None = Query(
None,
description="Window start (UTC). Defaults to start of current calendar month.",
),
until: datetime | None = Query(
None,
description="Window end (UTC). Defaults to now.",
),
top_runs_limit: int = Query(
10,
ge=1,
le=50,
description="Maximum number of top-cost runs to return.",
),
) -> UserExecutionCostSummary:
"""Aggregated cost breakdown for the calling user's graph executions."""
if since is not None and until is not None and since > until:
raise HTTPException(
status_code=422,
detail="`since` must be earlier than or equal to `until`.",
)
return await get_user_cost_summary(
user_id=user_id,
since=since,
until=until,
top_runs_limit=top_runs_limit,
)
@v1_router.get(
path="/graphs/{graph_id}/executions",
summary="List graph executions",
tags=["graphs"],
dependencies=[Security(requires_user)],
)
async def list_graph_executions(View on GitHub (pinned to 9c8bb5550f)
Solutions
- Validate/normalize the range client-side: if since > until, swap them or block submission.
- Check timezone handling — build both timestamps in the same (UTC) zone.
- Leave since/until omitted to default to a window ending now.
Example fix
// before
api.getCostSummary({ since: end, until: start }); // swapped
// after
const [lo, hi] = start <= end ? [start, end] : [end, start];
api.getCostSummary({ since: lo, until: hi }); Defensive patterns
Strategy: validation
Validate before calling
let [sinceN, untilN] = [since?.getTime() ?? -Infinity, until?.getTime() ?? Infinity];
if (sinceN > untilN) [sinceN, untilN] = [untilN, sinceN]; // or reject in the picker
await api.getCostSummary({ since: new Date(sinceN), until: new Date(untilN) }); Type guard
const isValidRange = (s?: Date, u?: Date) => !s || !u || s.getTime() <= u.getTime();
Try / catch
catch (e) { if (e.response?.status === 422 && /since/.test(e.response.data.detail)) { swapRangeAndRetry(); } else throw e; } Prevention
- Constrain the date picker so end < start cannot be submitted.
- Generate both bounds in UTC to avoid local-offset flips.
- Also keep top_runs_limit within [1,50] — Query metadata enforces it with its own 422.
When it happens
Trigger: Passing ?since=2026-08-10T00:00Z&until=2026-08-01T00:00Z — typically a date-picker allowing the user to select an end date before the start date, or timezone math that flips the boundaries.
Common situations: Analytics dashboards with free-form date range pickers; UTC-vs-local conversion bugs producing since one day after until; copy-pasted query params with swapped order.
Related errors
- Page must be greater than 0
- Page size must be greater than 0
- Title must not be blank
- builder_graph_id and expert_id are mutually exclusive
- Unsupported grant_type: {request.grant_type}. Must be 'autho
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/27715e9e24fff378.
Report an issue: GitHub.