ZhuLinsen/daily_stock_analysis · error · Error

发送失败

Error message

发送失败

What it means

Raised during quantity replay (_calculate_available_quantity, portfolio_service.py:749) when a split_adjustment event has split_ratio <= 0 (or null, since null coerces to 0.0). The replay cannot scale holdings by a non-positive factor, so the whole sell-validation/snapshot replay aborts with code=validation_error.

Source

Thrown at apps/dsa-web/src/api/agent.ts:111

    const response = await apiClient.get<{ sessions: ChatSessionItem[] }>('/api/v1/agent/chat/sessions', { params: { limit } });
    return response.data.sessions;
  },
  async getChatSessionMessages(sessionId: string): Promise<ChatSessionDetail> {
    const response = await apiClient.get<ChatSessionDetail>(`/api/v1/agent/chat/sessions/${sessionId}`);
    return response.data;
  },
  async deleteChatSession(sessionId: string): Promise<void> {
    await apiClient.delete(`/api/v1/agent/chat/sessions/${sessionId}`);
  },
  async sendChat(content: string): Promise<{ success: boolean }> {
    const response = await apiClient.post<{
      success: boolean;
      error?: string;
      message?: string;
    }>('/api/v1/agent/chat/send', { content });
    const data = response.data;
    if (data.success === false) {
      throw new Error(data.message || '发送失败');
    }
    return { success: true };
  },
  async chatStream(
    payload: ChatStreamRequest,
    options?: ChatStreamOptions,
  ): Promise<Response> {
    const base = API_BASE_URL || '';
    const url = `${base}/api/v1/agent/chat/stream`;
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
        credentials: 'include',
        signal: options?.signal,
      });

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Find and fix the offending row: query corporate actions for the symbol where split_ratio IS NULL or <= 0
  2. Delete the corrupt split_adjustment event if it was created by mistake
  3. Re-insert valid splits via add_corporate_action, which enforces split_ratio > 0 at write time
  4. Audit import tooling to skip (not zero-fill) missing split ratios

Example fix

# before
svc.add_corporate_action(account_id=1, symbol="AAPL", action_type="split_adjustment", split_ratio=0, ...)
# after
svc.add_corporate_action(account_id=1, symbol="AAPL", action_type="split_adjustment", split_ratio=2.0, ...)
Defensive patterns

Strategy: validation

Validate before calling

def split_ratio_ok(ratio):
    return ratio is not None and ratio > 0

Type guard

from numbers import Real

def is_valid_split_ratio(value: Real | None) -> bool:
    return value is not None and float(value) > 0.0

Try / catch

try:
    svc.get_snapshot(account_id=a)
except ValueError as exc:
    if "Invalid split_ratio" in str(exc):
        # quarantine the bad corporate action row and retry
        fix_bad_split_rows(a); svc.get_snapshot(account_id=a)
    else:
        raise

Prevention

When it happens

Trigger: A corporate_actions row with split_ratio = 0, negative, or NULL and action_type='split_adjustment' reaching the replay; rows written by an external tool or manual DB edit that bypassed add_corporate_action's validation; NaN serialized as 0.

Common situations: Manual SQLite/DB fixes that inserted placeholder 0 in split_ratio; import scripts that map a missing split column to 0 instead of skipping the row; an older code path that allowed null split_ratio before validation was added.

Related errors


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