{"record":{"id":"b19cd9aadc0a3f62","repo":"ZhuLinsen/daily_stock_analysis","slug":"invalid-params","errorCode":"invalid_params","errorMessage":"analysis_date_from cannot be after analysis_date_to","messagePattern":"analysis_date_from cannot be after analysis_date_to","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"api/v1/endpoints/backtest.py","lineNumber":36,"sourceCode":"    PerformanceMetrics,\n)\nfrom api.v1.schemas.common import ErrorResponse\nfrom src.services.backtest_service import BacktestService\nfrom src.storage import DatabaseManager\n\nlogger = logging.getLogger(__name__)\n\nrouter = APIRouter()\n\nBacktestAnalysisPhaseQuery = Literal[\"premarket\", \"intraday\", \"postmarket\", \"unknown\"]\n\n\ndef _validate_analysis_date_range(\n    analysis_date_from: Optional[date],\n    analysis_date_to: Optional[date],\n) -> None:\n    if analysis_date_from and analysis_date_to and analysis_date_from > analysis_date_to:\n        raise HTTPException(\n            status_code=400,\n            detail={\n                \"error\": \"invalid_params\",\n                \"message\": \"analysis_date_from cannot be after analysis_date_to\",\n            },\n        )\n\n\n@router.post(\n    \"/run\",\n    response_model=BacktestRunResponse,\n    responses={\n        200: {\"description\": \"回测执行完成\"},\n        400: {\"description\": \"请求参数错误\", \"model\": ErrorResponse},\n        500: {\"description\": \"服务器错误\", \"model\": ErrorResponse},\n    },\n    summary=\"触发回测\",\n    description=\"对历史分析记录进行回测评估，并写入 backtest_results/backtest_summaries\",","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/api/v1/endpoints/backtest.py#L18-L54","documentation":"Backtest endpoints call _validate_analysis_date_range (backtest.py:30-40) which returns HTTP 400 code=invalid_params when both analysis_date_from and analysis_date_to are supplied and from > to. It is a pure parameter-order sanity check executed before any service call, on /run, /results, /performance and /performance/{code}.","triggerScenarios":"Query params like ?analysis_date_from=2026-01-31&analysis_date_to=2026-01-01 on any backtest endpoint; date pickers whose end-date field is bound to the from parameter; timezone-less date strings parsed in unexpected order; form defaults where 'to' is yesterday and 'from' is today.","commonSituations":"Swapped date inputs in a custom UI; client sending ISO datetime strings where only dates are expected (FastAPI parses date, but value order can surprise); monthly-range widgets that emit first-day/end-day in the wrong fields.","solutions":["Swap or recompute the range client-side so from <= to before sending","Add client-side validation disabling submit when the range is inverted","If an inverted range should mean 'empty window', decide explicitly: either normalize (min/max) or refuse early — do not rely on the server to guess"],"exampleFix":"# before\nparams = {\"analysis_date_from\": end.isoformat(), \"analysis_date_to\": start.isoformat()}\n\n# after\nparams = {\n    \"analysis_date_from\": min(start, end).isoformat(),\n    \"analysis_date_to\": max(start, end).isoformat(),\n}","handlingStrategy":"validation","validationCode":"def assert_valid_range(d_from: date, d_to: date) -> None:\n    if d_from and d_to and d_from > d_to:\n        raise ValueError(\"analysis_date_from must be <= analysis_date_to\")\n\nassert_valid_range(analysis_date_from, analysis_date_to)\n# only now issue the backtest request","typeGuard":null,"tryCatchPattern":"try:\n    get_backtest(params)\nexcept HTTPError as e:\n    if e.response.status_code == 400 and 'cannot be after' in e.response.text:\n        params['analysis_date_from'], params['analysis_date_to'] = sorted(\n            [params['analysis_date_from'], params['analysis_date_to']])\n        get_backtest(params)\n    else:\n        raise","preventionTips":["Bind date pickers so end >= start is enforced in the UI","Run min/max normalization on any user-supplied range before building query params","Unit-test client param builders with inverted ranges"],"tags":["backtest","validation","http-400","date-range"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}