ZhuLinsen/daily_stock_analysis · error · HTTPException

invalid_request

invalid_request

Error message

stock_code 不能为空

What it means

This is a 400 invalid_request raised by DELETE /api/v1/history/by-code/{stock_code} when the stock_code path parameter normalizes to nothing. The endpoint calls HistoryService._history_code_filter_candidates(stock_code), which strips whitespace and returns [] only when the input is empty or whitespace-only (src/services/history_service.py:99-102). Any non-blank string, even a malformed code, produces at least one candidate, so this error fires almost exclusively on blank input.

Source

Thrown at api/v1/endpoints/history.py:318

    "/by-code/{stock_code}",
    response_model=DeleteHistoryResponse,
    responses={
        200: {"description": "删除成功"},
        400: {"description": "股票代码不能为空", "model": ErrorResponse},
        404: {"description": "未找到记录", "model": ErrorResponse},
        500: {"description": "服务器错误", "model": ErrorResponse},
    },
    summary="按股票代码删除历史分析记录",
    description="删除指定股票代码的所有分析历史记录(支持代码变体归一化匹配)",
)
def delete_history_by_code(
    stock_code: str,
    db_manager: DatabaseManager = Depends(get_database_manager),
) -> DeleteHistoryResponse:
    try:
        candidates = HistoryService._history_code_filter_candidates(stock_code)
        if not candidates:
            raise HTTPException(
                status_code=400,
                detail={"error": "invalid_request", "message": "stock_code 不能为空"},
            )

        deleted = 0
        while True:
            records, _ = db_manager.get_analysis_history_paginated(
                code=candidates,
                limit=_DELETE_BY_CODE_BATCH_SIZE,
            )
            record_ids = [r.id for r in records if r.id is not None]
            if not record_ids:
                break

            batch_deleted = db_manager.delete_analysis_history_records(record_ids)
            if batch_deleted == 0:
                raise RuntimeError("history deletion made no progress")
            deleted += batch_deleted

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Ensure the client has a non-empty stock code before issuing the request (guard with if (!stockCode?.trim()) ...).
  2. Verify the exact route: the code must be supplied as the stock_code path segment, e.g. DELETE /api/v1/history/by-code/600519.
  3. If the code comes from user input, trim it and reject blank values in the UI/script before calling the API.
  4. If you still get 400 with a visible code, confirm no proxy is stripping the path segment.

Example fix

// before
const res = await fetch(`/api/v1/history/by-code/${code}`, { method: 'DELETE' });

// after
const trimmed = (code ?? '').trim();
if (!trimmed) throw new Error('stock_code is required');
const res = await fetch(`/api/v1/history/by-code/${encodeURIComponent(trimmed)}`, { method: 'DELETE' });
Defensive patterns

Strategy: validation

Validate before calling

const code = String(stockCode ?? '').trim();
if (!code) {
  throw new Error('stock_code must be a non-empty stock code');
}
await fetch(`/api/v1/history/by-code/${encodeURIComponent(code)}`, { method: 'DELETE' });

Type guard

const isNonEmptyStockCode = (v: unknown): v is string =>
  typeof v === 'string' && v.trim().length > 0;

Try / catch

try { const res = await delByCode(code); if (res.status === 400) handleInvalidRequest(); } catch (e) { /* network only */ }

Prevention

When it happens

Trigger: Calling DELETE /history/by-code/ (empty path segment), /history/by-code/%20, or /history/by-code/%00-style whitespace-only values. A URL-encoded space or a client that builds the path from an unset/None stock variable (rendered as empty string) also triggers it.

Common situations: Frontend builds the delete URL from a state field that has not been initialized yet (empty string template interpolation); automated scripts iterating a list where some entries are empty strings; trailing-slash routing that maps to an empty path parameter

Related errors


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