{"record":{"id":"c6295c8e5f5c5f91","repo":"jingyaogong/minimind","slug":"str-e","errorCode":null,"errorMessage":"str(e)","messagePattern":"str\\(e\\)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"scripts/serve_openai_api.py","lineNumber":234,"sourceCode":"            if reasoning_content:\n                message[\"reasoning_content\"] = reasoning_content\n            if tool_calls:\n                message[\"tool_calls\"] = tool_calls\n            return {\n                \"id\": f\"chatcmpl-{int(time.time())}\",\n                \"object\": \"chat.completion\",\n                \"created\": int(time.time()),\n                \"model\": \"minimind\",\n                \"choices\": [\n                    {\n                        \"index\": 0,\n                        \"message\": message,\n                        \"finish_reason\": \"tool_calls\" if tool_calls else \"stop\"\n                    }\n                ]\n            }\n    except Exception as e:\n        raise HTTPException(status_code=500, detail=str(e))\n\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser(description=\"Server for MiniMind\")\n    parser.add_argument('--load_from', default='../model', type=str, help=\"模型加载路径（model=原生torch权重，其他路径=transformers格式）\")\n    parser.add_argument('--save_dir', default='out', type=str, help=\"模型权重目录\")\n    parser.add_argument('--weight', default='full_sft', type=str, help=\"权重名称前缀（pretrain, full_sft, dpo, reason, ppo_actor, grpo, spo）\")\n    parser.add_argument('--lora_weight', default='None', type=str, help=\"LoRA权重名称（None表示不使用，可选：lora_identity, lora_medical）\")\n    parser.add_argument('--hidden_size', default=768, type=int, help=\"隐藏层维度\")\n    parser.add_argument('--num_hidden_layers', default=8, type=int, help=\"隐藏层数量\")\n    parser.add_argument('--max_seq_len', default=8192, type=int, help=\"最大序列长度\")\n    parser.add_argument('--use_moe', default=0, type=int, choices=[0, 1], help=\"是否使用MoE架构（0=否，1=是）\")\n    parser.add_argument('--inference_rope_scaling', default=False, action='store_true', help=\"启用RoPE位置编码外推（4倍，仅解决位置编码问题）\")\n    parser.add_argument('--device', default='cuda' if torch.cuda.is_available() else 'cpu', type=str, help=\"运行设备\")\n    args = parser.parse_args()\n    device = args.device\n    model, tokenizer = init_model(args)\n    uvicorn.run(app, host=\"0.0.0.0\", port=8998)","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/jingyaogong/minimind/blob/393e387e9ad99f0f04c296e4c5e7353f4444629f/scripts/serve_openai_api.py#L216-L252","documentation":"This is a catch-all except inside the FastAPI /v1/chat/completions handler: any exception raised while running generation (tokenization, model forward pass, sampling, tool-call formatting) is re-raised as HTTPException(500, detail=str(e)). The 'str(e)' message is a placeholder artifact — the actual text is the string of whatever inner exception occurred, so the 500 carries no stable identifier. Diagnosing it requires reproducing the inner exception server-side.","triggerScenarios":"POSTing to the MiniMind OpenAI-compatible endpoint (serve_openai_api.py) with a request whose prompt exceeds max_seq_len (default 8192), a tool-call payload the formatting code cannot serialize, CUDA OOM on the forward pass, a missing/invalid weight path (--load_from default '../model' not present), or a tokenizer/model config mismatch (hidden_size=768/num_hidden_layers=8 not matching the checkpoint). Any of these raises inside the try block and surfaces as detail=str(e) with status 500.","commonSituations":"Running the server from a different working directory so '../model' resolves wrong; loading a full_sft/DPO checkpoint with wrong --hidden_size or --num_hidden_layers; sending messages longer than --max_seq_len; hitting a device mismatch (model on cuda, request path assumes cpu or vice versa); version drift between transformers and the saved checkpoint format.","solutions":["Run the server in the foreground and read the traceback printed before the HTTPException is raised — the 500 detail is only str(e), the real stack is server-side.","Verify --load_from path exists and matches the checkpoint format (torch weights vs transformers dir) and that --weight prefix names an existing file.","Check --hidden_size/--num_hidden_layers/--use_moe match the checkpoint config; a mismatch typically raises a tensor-shape error that becomes this 500.","Shorten the input below --max_seq_len (8192 default) or raise the flag if the GPU allows.","If it is CUDA OOM, reduce batch/seq length or move to a smaller quantization/beam setting.","Improve the handler: log the full traceback (logging.exception) and return a typed detail so clients can distinguish causes."],"exampleFix":"# before\nexcept Exception as e:\n    raise HTTPException(status_code=500, detail=str(e))\n\n# after\nexcept Exception as e:\n    logging.exception(\"chat completion failed\")\n    raise HTTPException(status_code=500, detail={\"error\": type(e).__name__, \"message\": str(e)})","handlingStrategy":"retry","validationCode":"# Before sending the real request, validate the server can generate\nimport requests\nhealth = requests.get(f\"{base_url}/health\", timeout=5)\nhealth.raise_for_status()\n# optional: probe with a 1-token request to surface model-loading errors cheaply\nprobe = requests.post(f\"{base_url}/v1/chat/completions\", json={\n    \"model\": \"minimind\", \"messages\": [{\"role\": \"user\", \"content\": \"hi\"}], \"max_tokens\": 1\n}, timeout=30)\nprobe.raise_for_status()","typeGuard":null,"tryCatchPattern":"from requests import HTTPError, RequestException\ntry:\n    r = requests.post(f\"{base_url}/v1/chat/completions\", json=payload, timeout=120)\n    r.raise_for_status()\n    result = r.json()\nexcept HTTPError as e:\n    if e.response.status_code == 500:\n        # detail is str(e) of an unknown inner exception: safe to retry once for transient\n        # causes (OOM recovery, racey load); if it persists, inspect server logs\n        time.sleep(2)\n        r = requests.post(f\"{base_url}/v1/chat/completions\", json=payload, timeout=120)\n        r.raise_for_status()\n        result = r.json()\n    else:\n        raise","preventionTips":["Keep prompts under the server's --max_seq_len; truncate client-side before sending.","Start serve_openai_api.py with verified --load_from/--weight paths and matching --hidden_size/--num_hidden_layers; check startup logs before accepting traffic.","Run the server in the foreground (or capture stderr) so the real traceback behind the 500 is available.","Monitor server GPU memory; OOM during generation is a frequent source of these 500s.","Patch the handler to logging.exception + typed detail so clients can branch on error class."],"tags":["fastapi","http-500","minimind","server","generic-exception"],"backgroundTag":null,"analyzedSha":"393e387e9ad99f0f04c296e4c5e7353f4444629f","analyzedAt":"2026-08-15T03:55:47.817Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}