ZhuLinsen/daily_stock_analysis · error · HTTPException
read_failed
read_failed
Error message
读取上传文件失败
What it means
Raised by /extract-from-image when reading the request body's underlying file object raises an unexpected exception (the HTTPException for size is re-raised untouched; everything else lands here). It wraps transport/stream errors during file.file.read into a controlled 400 with error code read_failed and logs a warning '读取上传文件失败'.
Source
Thrown at api/v1/endpoints/stocks.py:172
},
)
try:
# 先读取限定大小,再检查是否还有剩余(语义清晰:超出则拒绝)
data = file.file.read(MAX_SIZE_BYTES)
if file.file.read(1):
raise HTTPException(
status_code=400,
detail={
"error": "file_too_large",
"message": f"图片超过 {MAX_SIZE_BYTES // (1024 * 1024)}MB 限制",
},
)
except HTTPException:
raise
except Exception as e:
logger.warning(f"读取上传文件失败: {e}")
raise HTTPException(
status_code=400,
detail={"error": "read_failed", "message": "读取上传文件失败"},
)
try:
items, raw_text = extract_stock_codes_from_image(data, content_type)
extract_items = [
ExtractItem(code=code, name=name, confidence=conf) for code, name, conf in items
]
codes = [i.code for i in extract_items]
return ExtractFromImageResponse(
codes=codes,
items=extract_items,
raw_text=raw_text if include_raw else None,
)
except ValueError as e:
raise HTTPException(status_code=400, detail={"error": "extract_failed", "message": str(e)})
except Exception as e:View on GitHub (pinned to 5159bd72e8)
Solutions
- Retry the request — transient stream errors often succeed on a second attempt.
- Check proxy limits: set nginx client_max_body_size 6m and adequate proxy_read_timeout/proxy_send_timeout.
- Verify the API container has writable temp space and free disk for spooled uploads.
Example fix
# before (nginx) client_max_body_size 1m; # after client_max_body_size 6m; proxy_read_timeout 120s;
Defensive patterns
Strategy: retry
Try / catch
resp = None
for attempt in range(3):
try:
resp = requests.post(f'{base}/api/v1/stocks/extract-from-image',
files={'file': fh}, timeout=60)
if resp.status_code != 400 or resp.json().get('detail', {}).get('error') != 'read_failed':
break
except requests.RequestException:
pass
time.sleep(2 ** attempt)
assert resp is not None Prevention
- Keep nginx client_max_body_size above the app's 5MB image limit.
- Ensure the API host has writable temp space for spooled uploads.
- Treat read_failed as transient first; escalate only when retries keep failing.
When it happens
Trigger: Client aborts the upload mid-body so the multipart stream is truncated; a reverse proxy (nginx client_body_temp) fails or times out while streaming; spooled temp file deleted or unwritable (starlette spools >1MB to disk); malformed multipart chunking.
Common situations: nginx proxy with client_max_body_size smaller than the upload and interrupted transfers; disk-full on the API container's temp dir; flaky mobile networks dropping connections; load balancer idle timeouts during slow uploads.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/272504a1d72feb93.
Report an issue: GitHub.