datawhalechina/hello-agents · warning · HTTPException

议题不能为空

Error message

议题不能为空

What it means

The POST /api/debate handler in historical_review/web/app.py strips req.topic and raises HTTPException(400, '议题不能为空') when the result is empty. This is the web-layer twin of the orchestrator's ValueError (error 247): the endpoint validates the DebateRequest body before spending LLM tokens. A 400 here means the JSON body's topic field was missing, null, empty, or whitespace-only.

Source

Thrown at Co-creation-projects/meiguanxiHXX-historyReviewAgent/historical_review/web/app.py:80

@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)

    def _work() -> str:
        return run_historical_debate(
            topic,
            use_evidence_bundle=req.use_evidence_bundle,
            debate_temperature=req.debate_temperature,
            synthesizer_temperature=req.synthesizer_temperature,
            llm_api_key=req.api_key.strip() if req.api_key else None,
            llm_base_url=req.base_url.strip() if req.base_url else None,
            llm_model=req.model.strip() if req.model else None,
            llm_max_tokens=req.max_tokens,
            llm_timeout=req.timeout,
        )

View on GitHub (pinned to 606a07d341)

Solutions

  1. Send a real topic in the request body: curl -X POST /api/debate -H 'Content-Type: application/json' -d '{"topic":"评价隋炀帝", "api_key":"sk-or-..."}'.
  2. Add client-side validation: disable submit until topic.trim().length > 0.
  3. Make the Pydantic model enforce it — topic: str = Field(min_length=1) with a validator rejecting whitespace-only strings — so the 400 message is consistent for all callers.
  4. Handle HTTP 400 in the client and show the detail message to the user.

Example fix

# before
class DebateRequest(BaseModel):
    topic: str
# after
from pydantic import field_validator
class DebateRequest(BaseModel):
    topic: str
    @field_validator("topic")
    @classmethod
    def topic_not_blank(cls, v: str) -> str:
        if not v.strip():
            raise ValueError("议题不能为空")
        return v.strip()
Defensive patterns

Strategy: validation

Validate before calling

topic = (req.topic or "").strip()
if not topic:
    return JSONResponse(status_code=400, content={"detail": "议题不能为空"})

Type guard

def is_valid_debate_request(req) -> bool:
    return isinstance(getattr(req, "topic", None), str) and bool(req.topic.strip())

Try / catch

# client side
resp = requests.post(url, json=payload, timeout=60)
if resp.status_code == 400:
    show_user(resp.json()["detail"])  # display '议题不能为空' instead of crashing
else:
    resp.raise_for_status()

Prevention

When it happens

Trigger: curl -X POST /api/debate with {"topic": ""} or omitting topic; frontend submitting the form before the user types anything; a client sending topic: null; whitespace/punctuation-only input that strips to empty.

Common situations: Missing required-field check in the frontend form; automated scripts probing the API with empty payloads; textarea default value being empty string and validation living only server-side.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/349e8005b33c449d. Report an issue: GitHub.