{"record":{"id":"f59f20e341a02ba2","repo":"datawhalechina/hello-agents","slug":"user-id-f59f20","errorCode":null,"errorMessage":"user_id 无效","messagePattern":"user_id 无效","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/api/routes/diet.py","lineNumber":119,"sourceCode":"        diet_run_id=body.diet_run_id,\n        followed=body.followed,\n        reason_code=rc,\n        reason_detail=body.reason_detail,\n    )\n    asyncio.create_task(asyncio.to_thread(index_reflect_event, rid))\n    return {\n        \"ok\": True,\n        \"reflect_id\": rid,\n        \"user_id\": body.user_id,\n        \"diet_run_id\": body.diet_run_id,\n    }\n\n\n@router.get(\"/diet/users/{user_id}/runs\")\nasync def diet_runs(user_id: str, limit: int = 20):\n    uid = user_id.strip()\n    if not uid:\n        raise HTTPException(status_code=400, detail=\"user_id 无效\")\n    return {\"user_id\": uid, \"items\": list_diet_runs_for_user(uid, limit=limit)}\n\n\n@router.get(\"/diet/users/{user_id}/reflect_history\")\nasync def diet_reflect_history(user_id: str, limit: int = 20):\n    uid = user_id.strip()\n    if not uid:\n        raise HTTPException(status_code=400, detail=\"user_id 无效\")\n    return {\"user_id\": uid, \"items\": list_recent_diet_reflect(uid, limit=limit)}\n\n\n@router.get(\"/diet/runs/{run_id}\")\nasync def diet_run_detail(run_id: str):\n    row = get_diet_run(run_id.strip())\n    if not row:\n        raise HTTPException(status_code=404, detail=\"未找到该饮食推荐 run\")\n    return row\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/api/routes/diet.py#L101-L137","documentation":"HTTP 400 raised by GET /diet/users/{user_id}/runs when the path parameter, after .strip(), is empty. Because the route itself captures any non-empty path segment, in practice this fires only for URLs where the segment collapses to whitespace (e.g. '%20'), since a truly empty segment would not match the route.","triggerScenarios":"GET /diet/users/%20/rununs (URL-encoded space as user_id), or programmatic clients interpolating an unvalidated variable into the path.","commonSituations":"Client-side string interpolation of an empty/spaces variable into the URL template; manual curl with quotes around a space.","solutions":["Validate/trim user_id in the client before building the URL.","Send an actual identifier; a whitespace user_id is never meaningful.","Check for URL-encoding issues (%20) if you believe the id is non-empty."],"exampleFix":"# before\nuid = '   '\nrequests.get(f'{base}/diet/users/{uid}/runs')  # 400\n\n# after\nuid = current_user_id.strip()\nif not uid:\n    raise ValueError('user_id required')\nrequests.get(f'{base}/diet/users/{uid}/runs')","handlingStrategy":"validation","validationCode":"uid = user_id.strip()\nif not uid:\n    raise ValueError(\"user_id required\")\nurl = f\"{base}/diet/users/{quote(uid)}/runs\"","typeGuard":"def is_valid_path_user_id(v: str) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":null,"preventionTips":["Validate and trim path parameters before URL construction.","URL-encode path segments with urllib.parse.quote to avoid %20 ambiguity.","Centralize URL building for diet endpoints in one helper."],"tags":["fastapi","http-400","path-parameter","validation"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}