datawhalechina/hello-agents · error · HTTPException

user_id 与 run 不匹配

Error message

user_id 与 run 不匹配

What it means

HTTP 403 raised by POST /diet/runs/{run_id}/replay when an optional user_id is supplied in the body and, after stripping, does not equal the run's stored user_id. It prevents replaying another user's run under your identity; omitting user_id in the body skips the check entirely.

Source

Thrown at Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/api/routes/diet.py:164

        raise HTTPException(status_code=404, detail="未找到该饮食推荐 run")
    return build_diet_observability(row)


@router.post("/diet/runs/{run_id}/replay")
async def diet_run_replay(
    run_id: str,
    body: DietReplayRequest | None = Body(default=None),
):
    """
    阶段 3:用该 run 落库的 input 重跑流水线(新 run_id;列 replayed_from_run_id 与 output.replayed_from 溯源)。
    Mock 工具确定性较高,LLM 输出仍可能不同。
    """
    rid = run_id.strip()
    row = get_diet_run(rid)
    if not row:
        raise HTTPException(status_code=404, detail="run 不存在")
    if body and body.user_id and body.user_id.strip() != row["user_id"]:
        raise HTTPException(status_code=403, detail="user_id 与 run 不匹配")
    try:
        return await replay_diet_run(rid)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

View on GitHub (pinned to 606a07d341)

Solutions

  1. Send the same user_id that owns the run, or omit user_id from the replay body.
  2. Retrieve the owning user via GET /diet/runs/{run_id} if unsure.
  3. Normalize (trim) user_id client-side to avoid false mismatches.

Example fix

# before
requests.post(f'{base}/diet/runs/{rid}/replay', json={'user_id': 'bob'})  # 403

# after
requests.post(f'{base}/diet/runs/{rid}/replay', json={'user_id': 'alice'})
# or simply:
requests.post(f'{base}/diet/runs/{rid}/replay')
Defensive patterns

Strategy: validation

Validate before calling

row = requests.get(f"{base}/diet/runs/{rid}").json()
body = {"user_id": row["user_id"]} if include_owner else None
requests.post(f"{base}/diet/runs/{rid}/replay", json=body)

Try / catch

try:
    requests.post(f"{base}/diet/runs/{rid}/replay", json=body)
except HTTPError as e:
    if e.response.status_code == 403:
        body.pop("user_id", None)  # omit optional owner check and retry once
        requests.post(f"{base}/diet/runs/{rid}/replay")
    else:
        raise

Prevention

When it happens

Trigger: POST /diet/runs/{rid}/replay with body {"user_id": "bob"} for a run created by 'alice' — including whitespace/case mismatches.

Common situations: Client auto-injecting the current logged-in user into every request body; switching test users between recommend and replay.

Related errors


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