{"record":{"id":"6f4a0c3a294d2214","repo":"datawhalechina/hello-agents","slug":"diet-run-input","errorCode":null,"errorMessage":"diet run 不存在或缺少 input","messagePattern":"diet run 不存在或缺少 input","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/service/diet_recommend_service.py","lineNumber":33,"sourceCode":"\n    async def run(\n        self,\n        user_id: str,\n        context: Dict[str, Any],\n        *,\n        replayed_from_run_id: str | None = None,\n    ) -> Dict[str, Any]:\n        pipeline = DietMultiAgentPipeline()\n        return await pipeline.run(\n            user_id, context, replayed_from_run_id=replayed_from_run_id\n        )\n\n\nasync def replay_diet_run(original_run_id: str) -> Dict[str, Any]:\n    \"\"\"阶段 3：用历史 run 的 input 重跑流水线（新 run_id；溯源 replayed_from）。\"\"\"\n    row = get_diet_run(original_run_id.strip())\n    if not row or not isinstance(row.get(\"input\"), dict):\n        raise ValueError(\"diet run 不存在或缺少 input\")\n    svc = DietRecommendService()\n    return await svc.run(\n        row[\"user_id\"],\n        row[\"input\"],\n        replayed_from_run_id=original_run_id.strip(),\n    )\n","sourceCodeStart":15,"sourceCodeEnd":40,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Shawnxyxy-HealthRecordAgent/backend/service/diet_recommend_service.py#L15-L40","documentation":"ValueError raised by replay_diet_run when the stored row is missing (run id unknown) OR row['input'] is not a dict — i.e. the persisted input payload needed to re-execute the pipeline is absent/malformed. The route layer converts it to HTTP 400.","triggerScenarios":"POST /diet/runs/{run_id}/replay where the run row was deleted, or where the input column is NULL/JSON string instead of a dict (runs created before input persistence was added).","commonSituations":"Schema drift: old runs persisted before the 'input' column existed; storage writing input as a serialized string; deletion/cleanup jobs removing runs.","solutions":["Replay only runs created by the current version, which persist input as a dict.","If rows exist with stringified input, migrate them: parse the JSON string into a dict before replay.","Create a new run via /diet/recommend with the same context if the original input is unrecoverable."],"exampleFix":"# before\nawait replay_diet_run(old_run_id)  # ValueError: input column is NULL\n\n# after\nrow = get_diet_run(old_run_id)\ninp = row['input'] if isinstance(row.get('input'), dict) else json.loads(row['input'])\nif inp is None:\n    raise ValueError('original input not persisted; create a new run instead')","handlingStrategy":"validation","validationCode":"row = get_diet_run(run_id.strip())\nif not row or not isinstance(row.get(\"input\"), dict):\n    raise ValueError(\"cannot replay: run missing or input not persisted\")","typeGuard":"def is_replayable_run(row) -> bool:\n    return (\n        isinstance(row, dict)\n        and isinstance(row.get(\"input\"), dict)\n        and bool(row.get(\"user_id\"))\n    )","tryCatchPattern":"try:\n    new_run = await replay_diet_run(rid)\nexcept ValueError as e:\n    # route layer maps this to HTTP 400; distinguish missing-run vs missing-input\n    log.warning(\"replay rejected: %s\", e)\n    raise","preventionTips":["Persist the pipeline input as a JSON dict on every run from day one.","Migrate legacy rows: parse stringified inputs into dicts before replay.","Surface both failure modes (row missing, input malformed) distinctly in callers."],"tags":["python","replay","data-integrity","diet-api"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}