ruvnet/RuView · warning · HTTPException
End time must be after start time
Error message
End time must be after start time
What it means
HTTP 400 from POST /pose/historical when end_time <= start_time in HistoricalDataRequest. The comparison uses <=, so equal timestamps are rejected too — the range must be strictly positive. The check runs on parsed datetimes inside the handler, before the 7-day cap and before the query.
Source
Thrown at archive/v1/src/api/routers/pose.py:249
except Exception as e:
logger.error(f"Error getting zones summary: {e}")
raise HTTPException(
status_code=500,
detail="An internal error occurred. Please try again later."
)
@router.post("/historical")
async def get_historical_data(
request: HistoricalDataRequest,
pose_service: PoseService = Depends(get_pose_service),
current_user: Dict = Depends(require_auth)
):
"""Get historical pose estimation data."""
try:
# Validate time range
if request.end_time <= request.start_time:
raise HTTPException(
status_code=400,
detail="End time must be after start time"
)
# Limit query range to prevent excessive data
max_range = timedelta(days=7)
if request.end_time - request.start_time > max_range:
raise HTTPException(
status_code=400,
detail="Query range cannot exceed 7 days"
)
data = await pose_service.get_historical_data(
start_time=request.start_time,
end_time=request.end_time,
zone_ids=request.zone_ids,
aggregation_interval=request.aggregation_interval,
include_raw_data=request.include_raw_dataView on GitHub (pinned to 4685618388)
Solutions
- Fix or swap the fields so end_time > start_time
- If equal timestamps occur naturally (same-instant presets), nudge end_time by one interval (e.g. +1 second)
- Validate the range client-side before sending (see exampleFix)
Example fix
# before
body = {'start_time': iso_to, 'end_time': iso_from} # swapped
# after
assert iso_from < iso_to, 'end_time must be after start_time'
body = {'start_time': iso_from, 'end_time': iso_to} Defensive patterns
Strategy: validation
Validate before calling
from datetime import timedelta
def valid_range(start, end):
if end <= start:
raise ValueError('end_time must be after start_time')
if end - start > timedelta(days=7):
raise ValueError('range must be <= 7 days')
return start, end Type guard
def is_valid_time_range(start, end) -> bool:
return start is not None and end is not None and end > start Try / catch
resp = await client.post('/pose/historical', json=body)
if resp.status_code == 400 and 'after start time' in resp.json().get('detail', ''):
body['start_time'], body['end_time'] = min(body['start_time'], body['end_time']), max(body['start_time'], body['end_time'])
resp = await client.post('/pose/historical', json=body)
resp.raise_for_status() Prevention
- Validate ranges in the date picker before enabling submit
- Beware same-instant presets — nudge end by one interval
- Disable submit buttons when both boundaries are equal
When it happens
Trigger: POST /pose/historical with end_time equal to or earlier than start_time — e.g. a 'today' preset that produces start == end at midnight, or from/to fields wired in reverse.
Common situations: Date-range pickers returning the same boundary instant for both ends; from/to fields swapped in the client; timezone conversion collapsing both values to the same instant.
Related errors
- Query range cannot exceed 7 days
- Page must be >= 1
- Size must be >= 1
- Size must be <= {max_size}
- min_confidence must be between 0.0 and 1.0
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/df681be044caa076.
Report an issue: GitHub.