ZhuLinsen/daily_stock_analysis · warning · HTTPException

invalid_json

invalid_json

Error message

JSON 解析失败: {e}

What it means

Raised by POST /api/v1/stocks/parse-import when the request declares application/json but the body cannot be parsed by request.json(). Any JSONDecodeError-style failure is converted to HTTP 400 with error code invalid_json and the parser's message embedded; the raw parse error is also logged as a warning.

Source

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

    summary="解析 CSV/Excel/剪贴板",
    description="上传 CSV/Excel 文件或粘贴文本,自动解析股票代码。文件上限 2MB,文本上限 100KB。",
)
async def parse_import(request: Request) -> ExtractFromImageResponse:
    """
    解析 CSV/Excel 文件或剪贴板文本。

    - multipart/form-data + file: 上传文件
    - application/json + {"text": "..."}: 粘贴文本
    - 优先使用 file,若同时提供则忽略 text
    """
    content_type = (request.headers.get("content-type") or "").lower()

    if "application/json" in content_type:
        try:
            body = await request.json()
        except Exception as e:
            logger.warning("[parse_import] JSON parse failed: %s", e)
            raise HTTPException(
                status_code=400,
                detail={"error": "invalid_json", "message": f"JSON 解析失败: {e}"},
            )
        text = body.get("text") if isinstance(body, dict) else None
        if not text or not isinstance(text, str):
            raise HTTPException(
                status_code=400,
                detail={"error": "bad_request", "message": "未提供 text,请使用 {\"text\": \"...\"}"},
            )
        try:
            items = parse_import_from_text(text)
        except ValueError as e:
            text_bytes = len(text.encode("utf-8"))
            logger.warning(
                "[parse_import] parse_import_from_text failed: text_bytes=%d, error=%s",
                text_bytes,
                e,
            )

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Validate the body with JSON.parse (JS) or json.loads (Python) before sending, and log the exact payload on failure.
  2. Quote keys and use double quotes throughout: {"text": "..."}.
  3. Strip any BOM and ensure Content-Type matches the actual body format.

Example fix

# before
curl -X POST .../parse-import -H 'Content-Type: application/json' -d '{text: "600519"}'

# after
curl -X POST .../parse-import -H 'Content-Type: application/json' -d '{"text": "600519"}'
Defensive patterns

Strategy: validation

Validate before calling

let payload;
try { payload = JSON.parse(rawBodyText); } catch (e) {
  showError('JSON 格式错误: ' + e.message); return;
}
await fetch(url, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload)});

Type guard

function isJsonObject(v: unknown): v is Record<string, unknown> {
  if (typeof v !== 'object' || v === null || Array.isArray(v)) return false;
  try { JSON.parse(JSON.stringify(v)); return true; } catch { return false; }
}

Prevention

When it happens

Trigger: Sending text/plain or form-encoded data with a JSON content-type header; a body with trailing commas, single quotes, unescaped newlines, or a BOM prefix; an empty body with Content-Type: application/json; truncated JSON from a proxy.

Common situations: Hand-built curl -d '{text: "..."}' (unquoted key, single quotes); pasting JSON containing literal newlines inside strings; Windows editors adding a UTF-8 BOM; JS sending a stringified object twice (JSON.stringify(JSON.stringify(x))).

Related errors


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