{"record":{"id":"3a0201ff16aca1b6","repo":"datawhalechina/hello-agents","slug":"poi-str-e-3a0201","errorCode":null,"errorMessage":"获取POI详情失败: {str(e)}","messagePattern":"获取POI详情失败: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"code/chapter13/helloagents-trip-planner/backend/app/api/routes/poi.py","lineNumber":49,"sourceCode":"        \n    Returns:\n        POI详情响应\n    \"\"\"\n    try:\n        amap_service = get_amap_service()\n        \n        # 调用高德地图POI详情API\n        result = amap_service.get_poi_detail(poi_id)\n        \n        return POIDetailResponse(\n            success=True,\n            message=\"获取POI详情成功\",\n            data=result\n        )\n        \n    except Exception as e:\n        print(f\"❌ 获取POI详情失败: {str(e)}\")\n        raise HTTPException(\n            status_code=500,\n            detail=f\"获取POI详情失败: {str(e)}\"\n        )\n\n\n@router.get(\n    \"/search\",\n    summary=\"搜索POI\",\n    description=\"根据关键词搜索POI\"\n)\nasync def search_poi(keywords: str, city: str = \"北京\"):\n    \"\"\"\n    搜索POI\n\n    Args:\n        keywords: 搜索关键词\n        city: 城市名称\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/code/chapter13/helloagents-trip-planner/backend/app/api/routes/poi.py#L31-L67","documentation":"HTTPException(500) raised by GET /poi/{poi_id} (chapter13 poi routes) when amap_service.get_poi_detail(poi_id) throws. It wraps any failure in the Amap detail API call — bad id, key problems, network — into a 500 with the cause message.","triggerScenarios":"Passing a POI id that is not a valid Amap POIID (typo, internal id from another system); expired/unauthorized AMAP_API_KEY for the detail endpoint; network failure to restapi.amap.com.","commonSituations":"Frontend storing ids from a different source and replaying them; Amap key without the detail API whitelisted; ids captured from stale cached search results that Amap has since re-indexed.","solutions":["Verify the poi_id came from a prior /poi/search response in the same session","Check the server log '❌ 获取POI详情失败' line for the upstream error text","Confirm the API key supports the place/detail endpoint and has quota","Re-search the POI by keywords to obtain a fresh id, then fetch detail"],"exampleFix":"# before\nresp = requests.get(f'{BASE}/poi/poi-id-from-old-cache')  # 500\n\n# after\nsearch = requests.get(f'{BASE}/poi/search', params={'keywords': '故宫', 'city': '北京'}).json()\nfresh_id = search['data']['pois'][0]['id']\nresp = requests.get(f'{BASE}/poi/{fresh_id}')","handlingStrategy":"validation","validationCode":"import re\n\ndef is_amap_poi_id(pid: str) -> bool:\n    return bool(pid) and bool(re.fullmatch(r'[A-Z0-9]+', pid))\n\nassert is_amap_poi_id(poi_id), 'use an id returned by /poi/search'","typeGuard":"def is_amap_poi_id(pid) -> bool:\n    return isinstance(pid, str) and len(pid) >= 6 and pid.isalnum()","tryCatchPattern":"try:\n    r = requests.get(f'{BASE}/poi/{pid}', timeout=15)\n    r.raise_for_status()\nexcept requests.HTTPError as e:\n    if e.response.status_code == 500:\n        fresh = research_poi(name)  # re-search to get a current id\n        r = requests.get(f'{BASE}/poi/{fresh}', timeout=15)\n    raise","preventionTips":["Only pass ids obtained from a live /poi/search response","Re-search when detail lookups start failing — ids go stale","Treat detail-500 differently from search-500: the former is often id-related, the latter config-related"],"tags":["fastapi","http-500","amap","poi"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}