ZhuLinsen/daily_stock_analysis · error · SystemConfigValidationError

配置校验失败

Error message

配置校验失败

What it means

Raised during full account replay (portfolio_service.py:833) when a trade event has quantity <= 0 or price <= 0 (nulls coerce to 0.0). The replay needs positive qty and price to compute cash impact, cost basis, and PnL; a zero/negative value makes the whole snapshot fail with validation_error.

Source

Thrown at apps/dsa-web/src/api/systemConfig.ts:320

    return toCamelCase<DiscoverLLMChannelModelsResponse>(response.data);
  },

  async update(payload: UpdateSystemConfigRequest): Promise<UpdateSystemConfigResponse> {
    try {
      const response = await apiClient.put<Record<string, unknown>>(
        '/api/v1/system/config',
        toSnakeUpdatePayload(payload),
      );
      return toCamelCase<UpdateSystemConfigResponse>(response.data);
    } catch (error: unknown) {
      const parsed = getParsedApiError(error);
      if (error && typeof error === 'object' && 'response' in error) {
        const status = (error as { response?: { status?: number } }).response?.status;
        const payloadData = (error as { response?: { data?: unknown } }).response?.data;

        if (status === 400) {
          const validationError = toCamelCase<SystemConfigValidationErrorResponse>(payloadData ?? {});
          throw new SystemConfigValidationError(
            parsed.message || validationError.message || '配置校验失败',
            validationError.issues || [],
            parsed,
          );
        }

        if (status === 409) {
          const conflict = toCamelCase<SystemConfigConflictResponse>(payloadData ?? {});
          throw new SystemConfigConflictError(
            parsed.message || conflict.message || '配置版本冲突',
            conflict.currentConfigVersion,
            parsed,
          );
        }
      }

      throw error;
    }

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Find bad rows: query trades where quantity <= 0 OR price <= 0 OR price IS NULL for the account and fix or delete them
  2. For transfers/gifts, record a nominal positive price (e.g. cost basis) or model as a buy at the documented cost
  3. Re-write corrected rows through add_trade to get write-time validation
  4. Make the importer reject blank/zero prices instead of coercing to 0

Example fix

# before
svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=10, price=0, ...)
# after
svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=10, price=185.50, ...)
Defensive patterns

Strategy: validation

Validate before calling

def stored_trade_values_ok(qty, price):
    return qty is not None and qty > 0 and price is not None and price > 0

Type guard

from numbers import Real

def is_positive_price(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 trade quantity or price" in str(exc):
        fix_zero_price_trades(a); svc.get_snapshot(account_id=a)
    else:
        raise

Prevention

When it happens

Trigger: A trades row with quantity=0, price=0, price=NULL, or negative values reaching _replay_account; typically rows written by direct DB access or a buggy importer rather than through add_trade, which validates positivity at write time.

Common situations: Gifted/transferred share rows imported with price 0 because the source had no price; CSV import with blank price columns defaulted to 0; dev seeding with placeholder values; fee adjustments mis-modeled as zero-price trades.

Related errors


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