ZhuLinsen/daily_stock_analysis · error · ValueError

不支持的图片类型: {mime_type}。允许: {list(ALLOWED_MIME)}

Error message

不支持的图片类型: {mime_type}。允许: {list(ALLOWED_MIME)}

What it means

Validation error from extract_stock_codes_from_image: the normalized MIME type is not in ALLOWED_MIME (image/jpeg, image/png, image/webp, image/gif). The MIME string is lowercased and stripped of parameters (';'-suffix) before the check, so only genuinely unsupported types fail.

Source

Thrown at src/services/image_stock_extractor.py:367

    """
    从图片中提取股票代码及名称(使用 Vision LLM)。

    优先级:Gemini -> Anthropic -> OpenAI(首个可用)。
    支持多 Key 轮询与重试(最多 3 次,指数退避)。

    Args:
        image_bytes: 原始图片字节
        mime_type: MIME 类型(如 image/jpeg, image/png)

    Returns:
        (items, raw_text) - items 为 [(code, name?, confidence), ...],raw_text 为原始 LLM 响应。

    Raises:
        ValueError: 图片无效、未配置 Vision API 或提取失败时。
    """
    mime_type = (mime_type or "image/jpeg").strip().lower().split(";")[0].strip()
    if mime_type not in ALLOWED_MIME:
        raise ValueError(f"不支持的图片类型: {mime_type}。允许: {list(ALLOWED_MIME)}")

    if not image_bytes:
        raise ValueError("图片内容为空")

    if len(image_bytes) > MAX_SIZE_BYTES:
        raise ValueError(f"Image too large (max {MAX_SIZE_BYTES // (1024 * 1024)}MB)")

    _verify_image_magic_bytes(image_bytes, mime_type)

    image_b64 = base64.b64encode(image_bytes).decode("ascii")
    model = _resolve_vision_model()
    keys = _get_api_keys_for_model(model, get_config())

    last_error: Optional[Exception] = None
    for attempt in range(3):
        try:
            key = random.choice(keys) if keys else None
            raw = _call_litellm_vision(image_b64, mime_type, api_key=key)

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Convert the image to JPEG/PNG/WebP/GIF before calling (e.g. via Pillow: Image.open(x).convert('RGB').save(..., 'JPEG'))
  2. Reject unsupported types at the upload layer before backend submission
  3. If HEIC support is required, add server-side conversion since browsers can't decode HEIC

Example fix

# before
raw = extract_stock_codes_from_image(data, 'image/heic')  # ValueError
# after
from PIL import Image
import io
buf = io.BytesIO()
Image.open(io.BytesIO(data)).convert('RGB').save(buf, 'JPEG')
raw = extract_stock_codes_from_image(buf.getvalue(), 'image/jpeg')
Defensive patterns

Strategy: validation

Validate before calling

from src.services.image_stock_extractor import ALLOWED_MIME
mime = (mime_type or '').split(';')[0].strip().lower()
if mime not in ALLOWED_MIME:
    convert_with_pillow_then_retry()  # or reject at upload

Type guard

def is_supported_image_mime(m: str) -> bool:
    return (m or '').split(';')[0].strip().lower() in {
        'image/jpeg', 'image/png', 'image/webp', 'image/gif'}

Try / catch

try:
    extract_stock_codes_from_image(data, mime)
except ValueError as e:
    if '不支持的图片类型' in str(e):
        data, mime = convert_image(data)  # Pillow -> JPEG
        extract_stock_codes_from_image(data, mime)
    else:
        raise

Prevention

When it happens

Trigger: Passing mime_type like 'image/bmp', 'image/tiff', 'image/heic', 'image/x-icon', or a garbage string after normalization; passing None defaults to image/jpeg and passes.

Common situations: User uploads HEIC (iPhone photos) or BMP/TIFF/AVIF; front-end forwarding the file.type without restriction; misdetected MIME from upload middleware.

Related errors


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