{"record":{"id":"93ac8577ea50b945","repo":"datawhalechina/hello-agents","slug":"site-id-not-found-site-id-93ac85","errorCode":null,"errorMessage":"site_id not found: {site_id}","messagePattern":"site_id not found: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"Co-creation-projects/monkeyhlj-NetworkHealthReportAgent/src/api/main.py","lineNumber":65,"sourceCode":"    return {\"status\": \"ok\"}\n\n\n@app.get(\"/api/runtime\")\ndef runtime_status() -> dict:\n    return {\"runtime\": orchestrator.runtime_status()}\n\n\n@app.get(\"/api/sites\")\ndef list_sites() -> dict:\n    return {\"sites\": orchestrator.list_sites()}\n\n\n@app.get(\"/api/sites/{site_id}\")\ndef get_site(site_id: str) -> dict:\n    try:\n        return {\"site\": orchestrator.get_site(site_id)}\n    except ValueError as e:\n        raise HTTPException(status_code=404, detail=str(e)) from e\n\n\n@app.get(\"/api/reports/{site_id}\")\ndef get_site_report(\n    site_id: str,\n    start_date: str | None = Query(default=None, description=\"YYYY-MM-DD\"),\n    end_date: str | None = Query(default=None, description=\"YYYY-MM-DD\"),\n) -> dict:\n    start, end = default_date_window(start_date=start_date, end_date=end_date, days=7)\n    try:\n        report = orchestrator.build_report(site_id=site_id, start=start, end=end)\n        return {\"report\": report}\n    except ValueError as e:\n        raise HTTPException(status_code=404, detail=str(e)) from e\n\n\n@app.get(\"/api/reports\")\ndef get_all_site_reports(","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/monkeyhlj-NetworkHealthReportAgent/src/api/main.py#L47-L83","documentation":"GET /api/sites/{site_id} in src/api/main.py calls orchestrator.get_site and converts any ValueError into HTTPException(404) with the original message (\"site_id not found: ...\"). So the HTTP 404 you observe is a faithful re-raise of the orchestrator's unknown-site ValueError (error 252) — the route itself has no independent failure mode here. It means the path parameter does not match any site in the repository.","triggerScenarios":"curl http://host/api/sites/site-99 where site-99 is not in the dataset; URL-encoded or case-mismatched ids; a site deleted from the data source while the client held an old id; trailing whitespace in the path segment.","commonSituations":"Frontend caching an old site list; manual API exploration with guessed ids; copy-paste of ids between environments (dev data vs prod data differ).","solutions":["GET /api/sites first and copy a real site_id into the URL.","Compare the requested id with the listed ones for case/space/encoding differences.","If the site should exist, check that the API process loaded the same data directory the listing uses.","In clients, treat 404 on this route as 'unknown id' and refresh the site list."],"exampleFix":"# before\nr = requests.get(f\"{base}/api/sites/site-99\")\nr.raise_for_status()\n# after\nids = [s[\"site_id\"] for s in requests.get(f\"{base}/api/sites\").json()[\"sites\"]]\nassert \"site-99\" in ids, f\"unknown id, valid: {ids}\"\nr = requests.get(f\"{base}/api/sites/site-99\")\nr.raise_for_status()","handlingStrategy":"try-catch","validationCode":"ids = {s[\"site_id\"] for s in requests.get(f\"{base}/api/sites\").json()[\"sites\"]}\nif site_id not in ids:\n    raise LookupError(f\"{site_id} not in {sorted(ids)}\")","typeGuard":null,"tryCatchPattern":"resp = requests.get(f\"{base}/api/sites/{site_id}\")\nif resp.status_code == 404:\n    # unknown id: refresh the site list rather than retrying\n    sites = requests.get(f\"{base}/api/sites\").json()[\"sites\"]\n    raise LookupError(f\"site not found; available: {[s['site_id'] for s in sites]}\")\nresp.raise_for_status()","preventionTips":["Treat 404 on resource routes as stale-id signal; refresh the list","Validate ids client-side against a fresh /api/sites call","Log requested ids on 404 to detect encoding/case issues"],"tags":["fastapi","http-404","rest-api","domain-not-found","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}