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
- Convert the image to JPEG/PNG/WebP/GIF before calling (e.g. via Pillow: Image.open(x).convert('RGB').save(..., 'JPEG'))
- Reject unsupported types at the upload layer before backend submission
- 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
- Restrict the file input accept= attribute to image/jpeg,png,webp,gif
- Normalize HEIC/BMP/TIFF to JPEG server-side before extraction
- Run the same MIME normalization (lowercase, strip params) the backend uses
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
- unsupported_type
- 图片内容为空
- Image too large (max {MAX_SIZE_BYTES // (1024 * 1024)}MB)
- Backend executable not found: ${backendPath}
- Invalid share image record ID
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/2db0222dd4624f2a.
Report an issue: GitHub.