ZhuLinsen/daily_stock_analysis · warning · HTTPException

file_too_large

file_too_large

Error message

图片超过 {MAX_SIZE_BYTES // (1024 * 1024)}MB 限制

What it means

Raised by /extract-from-image when the uploaded image exceeds MAX_SIZE_BYTES (5MB per the route description). The handler reads exactly MAX_SIZE_BYTES, then probes one more byte; any extra byte proves the file is larger, so oversized files are rejected without loading them fully. HTTP 400 with error code file_too_large.

Source

Thrown at api/v1/endpoints/stocks.py:161

            status_code=400,
            detail={"error": "bad_request", "message": "未提供文件,请使用表单字段 file 上传图片"},
        )

    content_type = (file.content_type or "").split(";")[0].strip().lower()
    if content_type not in ALLOWED_MIME:
        raise HTTPException(
            status_code=400,
            detail={
                "error": "unsupported_type",
                "message": f"不支持的类型: {content_type}。允许: {ALLOWED_MIME_STR}",
            },
        )

    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 = [

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Compress or downscale the image client-side before upload (canvas resize or toBlob with quality ~0.8 JPEG).
  2. Enforce the same 5MB limit in the UI and show the size before submit.
  3. For PNG screenshots, convert to JPEG/WebP which typically shrinks well below 5MB.

Example fix

// before
fd.append('file', originalFile);

// after
async function shrink(file, maxBytes = 5 * 1024 * 1024) {
  if (file.size <= maxBytes) return file;
  const img = await createImageBitmap(file);
  const scale = Math.sqrt(maxBytes / file.size) * 0.95;
  const canvas = new OffscreenCanvas(Math.round(img.width * scale), Math.round(img.height * scale));
  canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
  return canvas.convertToBlob({type: 'image/jpeg', quality: 0.85});
}
fd.append('file', await shrink(originalFile));
Defensive patterns

Strategy: validation

Validate before calling

const MAX = 5 * 1024 * 1024;
if (file.size > MAX) {
  showError(`图片超过 5MB 限制(当前 ${(file.size / 1048576).toFixed(1)}MB)`);
  return;
}

Type guard

function isWithinImageLimit(file: File, max = 5 * 1024 * 1024): boolean {
  return file.size <= max;
}

Prevention

When it happens

Trigger: POSTing an image >5MB; images between exactly 5MB and 5MB+1 byte (the boundary is inclusive: a file of exactly MAX_SIZE_BYTES passes); screenshots from retina displays saved as lossless PNG.

Common situations: Long trading screenshots concatenated into one tall PNG; scanned broker statements; users on mobile uploading original camera photos; GIFs with many frames.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/005933a8d20ea3f1. Report an issue: GitHub.