{"record":{"id":"534f82b0cb1f78ca","repo":"datawhalechina/hello-agents","slug":"str-e-534f82","errorCode":null,"errorMessage":"处理失败: {str(e)}","messagePattern":"处理失败: \\{str\\(e\\)\\}","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"Co-creation-projects/Apricity-InnocoreAI/api/routes/writing.py","lineNumber":138,"sourceCode":"        prompt = prompts.get(request.task, prompts[\"polish\"])\n        \n        # 调用 LLM 处理\n        response = await llm.ainvoke(prompt)\n        result_content = response.content if hasattr(response, 'content') else str(response)\n        \n        return {\n            \"success\": True,\n            \"task\": request.task,\n            \"style\": request.style,\n            \"original\": request.text,\n            \"result\": result_content\n        }\n        \n    except HTTPException:\n        raise\n    except Exception as e:\n        logger.error(f\"写作助手处理失败: {str(e)}\")\n        raise HTTPException(status_code=500, detail=f\"处理失败: {str(e)}\")\n\n@router.post(\"/explain\", response_model=Dict[str, Any])\nasync def explain_concept(request: ExplainRequest):\n    \"\"\"解释复杂概念\"\"\"\n    try:\n        # 模拟概念解释\n        return {\n            \"success\": True,\n            \"concept\": request.concept,\n            \"explanation\": f\"[Detailed explanation of {request.concept} in accessible terms while maintaining technical accuracy]\",\n            \"examples\": [\"Example 1\", \"Example 2\"],\n            \"timestamp\": \"2024-01-15T10:30:00Z\"\n        }\n        \n    except Exception as e:\n        logger.error(f\"概念解释失败: {str(e)}\")\n        raise HTTPException(status_code=500, detail=str(e))\n","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Apricity-InnocoreAI/api/routes/writing.py#L120-L156","documentation":"A generic 500 from the /writing/coach endpoint in api/routes/writing.py wrapping any non-HTTPException error raised while running the writing task. In practice the raising code is the LLM call (network failure, timeout, quota, malformed response), since the rest of the handler only formats strings. The handler correctly re-raises HTTPException untouched (line 'except HTTPException: raise'), so this 500 always originates from the underlying AI client or response parsing.","triggerScenarios":"POST /writing/coach where llm.ainvoke/completion raises: expired or invalid API key (401), rate limit (429), network timeout to the OpenAI-compatible endpoint, or response.content being None/empty so result_content extraction raises AttributeError/KeyError. An unknown request.task falling through a prompt dict lookup could also KeyError before the guard.","commonSituations":"Expired API key mid-deployment; shared key hitting rate limits under load; self-hosted LLM gateway temporarily down; model name in config not available on the endpoint; response shape differs from expected (e.g. reasoning models returning empty content) causing the extraction code to raise.","solutions":["Check server logs for the logged line '写作助手处理失败: ...' — str(e) names the real cause (auth, timeout, rate limit)","Retry once after a short delay for transient network/429 errors, or add exponential backoff around the LLM call","Validate request.task against the supported set ('polish', etc.) before building prompts, returning 422 for unknown tasks","Guard result_content extraction: use response.choices[0].message.content or the SDK's typed accessor, defaulting to a clear message when content is empty","Do not echo str(e) to clients — return a generic message and keep details in logs"],"exampleFix":"# before\nexcept Exception as e:\n    logger.error(f\"写作助手处理失败: {str(e)}\")\n    raise HTTPException(status_code=500, detail=f\"处理失败: {str(e)}\")\n\n# after\nfrom openai import APIConnectionError, RateLimitError, AuthenticationError\nexcept (RateLimitError, APIConnectionError):\n    raise HTTPException(status_code=503, detail=\"AI service temporarily unavailable, retry later\")\nexcept AuthenticationError:\n    raise HTTPException(status_code=502, detail=\"AI credentials rejected\")\nexcept Exception:\n    logger.exception(\"写作助手处理失败\")\n    raise HTTPException(status_code=500, detail=\"处理失败\")","handlingStrategy":"retry","validationCode":"valid_tasks = {'polish', 'rewrite', 'expand'}\nif request.task not in valid_tasks:\n    return HTTP 422 before calling the endpoint","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        return client.post('/writing/coach', json=payload)\n    except HTTPError as e:\n        if e.response.status_code == 500 and attempt < 2:\n            time.sleep(2 ** attempt); continue\n        raise","preventionTips":["Treat 500s here as transient first (rate limit/network) — retry with backoff once or twice","Log the response body server-side correlation id for diagnosis; the handler logs the root cause","Keep the task/style vocabulary fixed between client and server to avoid lookup errors"],"tags":["openai","http-500","error-handling","rate-limit","fastapi"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}