ZhuLinsen/daily_stock_analysis · warning · HTTPException

unsupported_type

unsupported_type

Error message

不支持的类型: {content_type}。允许: {ALLOWED_MIME_STR}

What it means

Raised by /extract-from-image when the upload's Content-Type (after stripping parameters like ;charset=utf-8 and lowercasing) is not in ALLOWED_MIME, the set imported from src/services/image_stock_extractor.py (JPEG, PNG, WebP, GIF per the route description). HTTP 400 with error code unsupported_type.

Source

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

)
def extract_from_image(
    file: Optional[UploadFile] = File(None, description="图片文件(表单字段名 file)"),
    include_raw: bool = Query(False, description="是否在结果中包含原始 LLM 响应"),
) -> ExtractFromImageResponse:
    """
    从上传的图片中提取股票代码(使用 Vision LLM)。

    表单字段请使用 file 上传图片。优先级:Gemini / Anthropic / OpenAI(首个可用)。
    """
    if not file or not file.filename:
        raise HTTPException(
            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 限制",
                },
            )

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Convert the image to JPEG/PNG/WebP/GIF before upload (e.g. canvas.toBlob('image/png') in JS, or convert HEIC on the client).
  2. Ensure the client sets the correct Content-Type per part; when the browser cannot detect it, explicitly supply type in new File([blob], 'x.png', {type: 'image/png'}).
  3. Check the echoed value in the error message ('不支持的类型: ...') to see what type actually arrived.

Example fix

# before
curl -F 'file=@photo.heic' .../extract-from-image  # unsupported_type

# after
# convert first: heif-convert photo.heic photo.jpg
curl -F 'file=@photo.jpg' .../extract-from-image
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
const type = (file.type || '').split(';')[0].trim().toLowerCase();
if (!ALLOWED.includes(type)) {
  showError(`不支持的类型: ${type || '未知'},请使用 JPEG/PNG/WebP/GIF`);
  return;
}

Type guard

function isAllowedImageType(file: File): boolean {
  const t = (file.type || '').split(';')[0].trim().toLowerCase();
  return ['image/jpeg', 'image/png', 'image/webp', 'image/gif'].includes(t);
}

Prevention

When it happens

Trigger: Uploading a BMP, TIFF, HEIC, SVG, or AVIF file; uploading a file renamed to .png whose real Content-Type is application/octet-stream; a client that defaults to text/plain when it cannot sniff the type.

Common situations: iPhone screenshots in HEIC not converted by the browser; files dragged from design tools as SVG; servers/clients that send generic application/octet-stream; double-extension files like photo.png.exe misdetected.

Related errors


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