ZhuLinsen/daily_stock_analysis · error · ValueError
validation_error
validation_error
Error message
symbol must not be empty
What it means
ValueError('symbol must not be empty') raised inside _resolve_position_analysis_context and mapped to a 400 validation_error by POST /portfolio/positions/{symbol}/analysis (portfolio.py:457-458). The path symbol is passed through PortfolioService._normalize_symbol_for_position; when normalization yields an empty string — empty/whitespace path segment, or a symbol consisting solely of characters normalization strips — the ValueError fires before any position lookup.
Source
Thrown at api/v1/endpoints/portfolio.py:503
response = TaskAccepted(
task_id=task.task_id,
trace_id=task.trace_id or task.task_id,
status="pending",
message=f"分析任务已加入队列: {task.stock_code}",
analysis_phase=task.analysis_phase,
)
return response
def _resolve_position_analysis_context(
service: PortfolioService,
*,
symbol: str,
account_id: Optional[int],
) -> dict:
target = service._normalize_symbol_for_position(symbol)
if not target:
raise ValueError("symbol must not be empty")
snapshot = service.get_portfolio_snapshot(account_id=account_id, cost_method="fifo")
matches = []
for account in snapshot.get("accounts") or []:
for position in account.get("positions") or []:
position_symbol = service._normalize_symbol_for_position(
str(position.get("symbol") or "")
)
if position_symbol != target:
continue
try:
quantity = float(position.get("quantity") or 0)
except (TypeError, ValueError):
quantity = 0.0
if quantity <= 0:
continue
matches.append((account, position, position_symbol))
View on GitHub (pinned to 5159bd72e8)
Solutions
- Validate and trim the symbol client-side before POSTing; require a non-empty result.
- URL-encode the symbol: /portfolio/positions/{encodeURIComponent(symbol)}/analysis.
- If a legitimate symbol normalizes to empty, check _normalize_symbol_for_position's rules for that market's format (e.g. HK/A股 prefixes) and use the canonical form.
Example fix
# before
requests.post(f"{base}/portfolio/positions/{symbol}/analysis", json={})
# after
symbol = (symbol or '').strip()
if not symbol:
raise ValueError('symbol is required')
requests.post(f"{base}/portfolio/positions/{quote(symbol)}/analysis", json={}) Defensive patterns
Strategy: validation
Validate before calling
const symbol = String(rawSymbol ?? '').trim();
if (!/^([0-9]{5,6}|[A-Z.\-]{1,12})$/i.test(symbol)) {
throw new Error('symbol must be a non-empty ticker');
}
await fetch(`/portfolio/positions/${encodeURIComponent(symbol)}/analysis`, { method: 'POST', body: '{}' }); Type guard
const isNonEmptySymbol = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0;
Try / catch
try { await analyzePosition(symbol); }
catch (e) { if (isHttp400(e) && /symbol must not be empty/.test(e.message)) flagBadSymbolInput(); } Prevention
- Trim and validate the symbol before building the path; disable submit on empty.
- Always encodeURIComponent path parameters.
- Use the symbol exactly as returned by the portfolio snapshot/positions endpoints so normalization matches.
- Expect a 400 ValueError mapping here, a 404 when no non-zero position exists, and a 400 ambiguous_position_account when the symbol spans multiple accounts — handle each distinctly.
When it happens
Trigger: POST /portfolio/positions//analysis (empty path segment); a symbol of only spaces or only punctuation that normalization reduces to ''; URL-encoded whitespace (%20) as the symbol; client interpolating an unset variable into the path.
Common situations: Frontend submitting before the symbol state is populated; scripts iterating symbol lists containing blanks; copy/paste introducing invisible characters that normalize away.
Related errors
- Backend executable not found: ${backendPath}
- Desktop backend URL is unavailable
- Desktop share image has invalid dimensions: ${pageMetrics.wi
- invalid_params
- invalid_request
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/75ad7700be3c8cb2.
Report an issue: GitHub.