datawhalechina/hello-agents · warning · HTTPException
site_id not found: {site_id}
Error message
site_id not found: {site_id} What it means
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.
Source
Thrown at Co-creation-projects/monkeyhlj-NetworkHealthReportAgent/src/api/main.py:65
return {"status": "ok"}
@app.get("/api/runtime")
def runtime_status() -> dict:
return {"runtime": orchestrator.runtime_status()}
@app.get("/api/sites")
def list_sites() -> dict:
return {"sites": orchestrator.list_sites()}
@app.get("/api/sites/{site_id}")
def get_site(site_id: str) -> dict:
try:
return {"site": orchestrator.get_site(site_id)}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e)) from e
@app.get("/api/reports/{site_id}")
def get_site_report(
site_id: str,
start_date: str | None = Query(default=None, description="YYYY-MM-DD"),
end_date: str | None = Query(default=None, description="YYYY-MM-DD"),
) -> dict:
start, end = default_date_window(start_date=start_date, end_date=end_date, days=7)
try:
report = orchestrator.build_report(site_id=site_id, start=start, end=end)
return {"report": report}
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e)) from e
@app.get("/api/reports")
def get_all_site_reports(View on GitHub (pinned to 606a07d341)
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.
Example fix
# before
r = requests.get(f"{base}/api/sites/site-99")
r.raise_for_status()
# after
ids = [s["site_id"] for s in requests.get(f"{base}/api/sites").json()["sites"]]
assert "site-99" in ids, f"unknown id, valid: {ids}"
r = requests.get(f"{base}/api/sites/site-99")
r.raise_for_status() Defensive patterns
Strategy: try-catch
Validate before calling
ids = {s["site_id"] for s in requests.get(f"{base}/api/sites").json()["sites"]}
if site_id not in ids:
raise LookupError(f"{site_id} not in {sorted(ids)}") Try / catch
resp = requests.get(f"{base}/api/sites/{site_id}")
if resp.status_code == 404:
# unknown id: refresh the site list rather than retrying
sites = requests.get(f"{base}/api/sites").json()["sites"]
raise LookupError(f"site not found; available: {[s['site_id'] for s in sites]}")
resp.raise_for_status() Prevention
- 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
When it happens
Trigger: 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.
Common situations: Frontend caching an old site list; manual API exploration with guessed ids; copy-paste of ids between environments (dev data vs prod data differ).
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/93ac8577ea50b945.
Report an issue: GitHub.