datawhalechina/hello-agents · error · HTTPException
前端文件缺失,请检查 historical_review/web/static/
Error message
前端文件缺失,请检查 historical_review/web/static/
What it means
The FastAPI index route resolves historical_review/web/static/index.html via pathlib and raises HTTPException(500, '前端文件缺失...') when the file is not a regular file. The backend itself is healthy — this is a packaging/deployment error: the static frontend asset was not shipped alongside the Python package. Because it is raised on GET /, the whole UI appears broken even though /api/health works.
Source
Thrown at Co-creation-projects/meiguanxiHXX-historyReviewAgent/historical_review/web/app.py:67
class DebateResponse(BaseModel):
ok: bool
markdown: str | None = None
error: str | None = None
def _api_key_error(req: DebateRequest) -> str | None:
has_key = bool(req.api_key and req.api_key.strip())
if not has_key and not (os.getenv("OPENROUTER_API_KEY") or os.getenv("LLM_API_KEY")):
return "未配置 API Key:请在左侧填写 OpenRouter Key,或在服务器 .env 中设置 OPENROUTER_API_KEY。"
return None
@app.get("/")
async def index_page() -> FileResponse:
html = _STATIC / "index.html"
if not html.is_file():
raise HTTPException(status_code=500, detail="前端文件缺失,请检查 historical_review/web/static/")
return FileResponse(html)
@app.get("/api/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/api/debate", response_model=DebateResponse)
async def run_debate(req: DebateRequest) -> DebateResponse:
topic = req.topic.strip()
if not topic:
raise HTTPException(status_code=400, detail="议题不能为空")
key_err = _api_key_error(req)
if key_err:
return DebateResponse(ok=False, error=key_err)
View on GitHub (pinned to 606a07d341)
Solutions
- Check the filesystem: ls historical_review/web/static/ — if index.html is absent, restore it from git (git checkout -- historical_review/web/static/) or run the frontend build that produces it.
- Run the server from the package root (where historical_review/ resolves) or anchor _STATIC to the module file: Path(__file__).parent / "static".
- For packaging, add package-data entries ("static/*" under historical_review.web) in pyproject/setup.py and build with the files included.
- In Docker, ensure COPY includes the static directory (COPY historical_review/ historical_review/).
- Sanity-check deployments with GET /api/health (ok) vs GET / (500) to distinguish backend vs asset problems.
Example fix
# before
_STATIC = Path("historical_review/web/static") # cwd-dependent
# after
_STATIC = Path(__file__).resolve().parent / "static" # anchored to app.py
html = _STATIC / "index.html"
if not html.is_file():
raise HTTPException(status_code=500, detail=f"前端文件缺失: {html}") Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
_STATIC = Path(__file__).resolve().parent / "static"
html = _STATIC / "index.html"
if not html.is_file():
raise SystemExit(f"static frontend missing at {html} — restore it or fix packaging") Try / catch
from fastapi import HTTPException
try:
return FileResponse(html)
except (FileNotFoundError, RuntimeError) as e:
raise HTTPException(status_code=500, detail=f"frontend asset failure: {e}") from e Prevention
- Anchor static dirs to __file__, never to cwd
- Include static assets in package_data / Docker COPY
- Add a deploy-time smoke test: GET / must return 200
When it happens
Trigger: Running the app from a different working directory so the relative _STATIC path resolves elsewhere; installing the package without package_data/include-package-data so static/ is excluded from the wheel; a Docker image that copies *.py but not historical_review/web/static/; a repo checkout where the static folder was gitignored or deleted.
Common situations: pip install from a wheel/sdist that forgot static assets; docker build with COPY src/ only; running uvicorn with an odd --app-dir; frontend build step never ran (if index.html is generated rather than committed).
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/5e4c55ae1a36a6e0.
Report an issue: GitHub.