ZhuLinsen/daily_stock_analysis · warning · HTTPException
invalid_stock_code
invalid_stock_code
Error message
股票代码不能为空
What it means
Raised by _validate_and_normalize_stock_code in the watchlist add/remove endpoints when the submitted stock_code is empty or only whitespace after stripping. It is a client-side validation error returned as HTTP 400 with error code invalid_stock_code. The check runs before any regex matching or persistence, so it never touches backend state.
Source
Thrown at api/v1/endpoints/stocks.py:98
r"|(?:SH|SZ|BJ)\d{6}" # exchange-prefixed A-share
r"|\d{6}\.(?:SH|SZ|SS|BJ)" # exchange-suffixed A-share
r"|\d{1,5}\.HK" # HK suffix format
r"|HK\d{1,5}" # HK prefix format
r"|\d{5}" # bare 5-digit HK code
r"|[A-Z]{1,5}(?:\.(?:US|[A-Z]))?" # US ticker
r")$",
re.IGNORECASE,
)
def _validate_and_normalize_stock_code(code: str) -> str:
"""Validate stock code format and return canonical form.
Raises HTTPException(400) if the code does not match supported formats.
"""
stripped = code.strip()
if not stripped:
raise HTTPException(
status_code=400,
detail={"error": "invalid_stock_code", "message": "股票代码不能为空"},
)
if not _STOCK_CODE_RE.match(stripped):
raise HTTPException(
status_code=400,
detail={
"error": "invalid_stock_code",
"message": f"'{stripped}' 不是合法的股票代码格式",
},
)
return normalize_stock_code(stripped)
def _watchlist_match_key(code: str) -> str:
"""Return the equivalence key used for watchlist add/remove matching."""
normalized = normalize_stock_code(code.strip())
if re.fullmatch(r"\d{5}", normalized):View on GitHub (pinned to 5159bd72e8)
Solutions
- Trim the input client-side and disable the submit action when stock_code.strip() is empty.
- Add a required-field check in the request schema (e.g. Pydantic min_length=1 with a strip validator) so FastAPI rejects it with 422 before the handler runs.
- If scripting, assert the variable is non-empty before calling the endpoint.
Example fix
// before
const code = codeInput.value;
await fetch(`/api/v1/stocks/watchlist/add`, {method:'POST', body: JSON.stringify({stock_code: code})});
// after
const code = codeInput.value.trim();
if (!code) { setFormError('请输入股票代码'); return; }
await fetch(`/api/v1/stocks/watchlist/add`, {method:'POST', body: JSON.stringify({stock_code: code})}); Defensive patterns
Strategy: validation
Validate before calling
const code = String(rawInput || '').trim();
if (!code) {
showFormError('股票代码不能为空');
return;
}
// safe to POST /watchlist/add Type guard
function isNonEmptyStockCode(v: unknown): v is string {
return typeof v === 'string' && v.trim().length > 0;
} Prevention
- Trim input before every watchlist API call.
- Mark the stock_code field required in the UI and disable submit while empty.
- Add a Pydantic min_length/strip validator on WatchlistRequest so the schema layer rejects empties.
When it happens
Trigger: POST /api/v1/stocks/watchlist/add or /watchlist/remove with body {"stock_code": ""} or {"stock_code": " "}; a frontend form submitted without user input; an automation script passing an unset variable that resolves to an empty string.
Common situations: Web form submit button enabled with an empty input field; JS code sending request.stock_code before assigning it; whitespace-only input pasted from a spreadsheet; default value of a dropdown/select left blank.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/dd23c2b82b24855e.
Report an issue: GitHub.