ZhuLinsen/daily_stock_analysis · error · Error

请提供文件或粘贴文本

Error message

请提供文件或粘贴文本

What it means

Raised during full account replay (_replay_account, portfolio_service.py:819) when a cash event's direction is neither 'in' nor 'out'. The replay must decide whether to add or subtract the amount; an unknown direction aborts the entire snapshot computation with validation_error.

Source

Thrown at apps/dsa-web/src/api/stocks.ts:52

      rawText: data.raw_text,
    };
  },

  async parseImport(file?: File, text?: string): Promise<ExtractFromImageResponse> {
    if (file) {
      const formData = new FormData();
      formData.append('file', file);
      const headers: { [key: string]: string | undefined } = { 'Content-Type': undefined };
      const response = await apiClient.post('/api/v1/stocks/parse-import', formData, { headers });
      const data = response.data as { codes?: string[]; items?: ExtractItem[] };
      return { codes: data.codes ?? [], items: data.items };
    }
    if (text) {
      const response = await apiClient.post('/api/v1/stocks/parse-import', { text });
      const data = response.data as { codes?: string[]; items?: ExtractItem[] };
      return { codes: data.codes ?? [], items: data.items };
    }
    throw new Error('请提供文件或粘贴文本');
  },
};

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Query cash_events for the account where direction IS NULL or NOT IN ('in','out') and repair the rows
  2. Normalize legacy rows: UPDATE cash_events SET direction = LOWER(TRIM(direction)) and map synonyms to in/out
  3. Route all new writes through add_cash_event, which validates against VALID_CASH_DIRECTIONS
  4. Add an audit query after bulk imports

Example fix

# before
raw_insert(direction="DEPOSIT", amount=1000.0)
# after
svc.add_cash_event(account_id=1, direction="in", amount=1000.0, event_date=d, ...)
Defensive patterns

Strategy: validation

Validate before calling

VALID_CASH_DIRECTIONS = {"in", "out"}

def stored_direction_ok(direction):
    return bool(direction) and direction.strip().lower() in VALID_CASH_DIRECTIONS

Type guard

from typing import Literal, TypeGuard

StoredCashDirection = Literal["in", "out"]

def is_stored_cash_direction(value: str | None) -> TypeGuard[StoredCashDirection]:
    return bool(value) and value.strip().lower() in {"in", "out"}

Try / catch

try:
    svc.get_snapshot(account_id=a)
except ValueError as exc:
    if "Unsupported cash direction" in str(exc):
        normalize_cash_directions_in_db(a); svc.get_snapshot(account_id=a)
    else:
        raise

Prevention

When it happens

Trigger: A cash_events row with direction='IN ' with trailing characters that break the exact match (note: unlike the query path, this check is exact, not lowercased), direction='deposit', direction=NULL, or any non-enum value written outside add_cash_event's validated path.

Common situations: Direct DB inserts from migration scripts using debit/credit vocabulary; importer defaulting missing direction to NULL; a legacy writer that stored 'IN'/'OUT' uppercase before normalization was added at the write boundary — this replay branch compares event.direction == 'in' exactly.

Related errors


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