{"record":{"id":"962833e2eddc86f8","repo":"ZhuLinsen/daily_stock_analysis","slug":"error-962833","errorCode":null,"errorMessage":"配置校验失败","messagePattern":"配置校验失败","errorType":"validation","errorClass":"SystemConfigValidationError","httpStatus":400,"severity":"error","filePath":"apps/dsa-web/src/api/systemConfig.ts","lineNumber":320,"sourceCode":"    return toCamelCase<DiscoverLLMChannelModelsResponse>(response.data);\n  },\n\n  async update(payload: UpdateSystemConfigRequest): Promise<UpdateSystemConfigResponse> {\n    try {\n      const response = await apiClient.put<Record<string, unknown>>(\n        '/api/v1/system/config',\n        toSnakeUpdatePayload(payload),\n      );\n      return toCamelCase<UpdateSystemConfigResponse>(response.data);\n    } catch (error: unknown) {\n      const parsed = getParsedApiError(error);\n      if (error && typeof error === 'object' && 'response' in error) {\n        const status = (error as { response?: { status?: number } }).response?.status;\n        const payloadData = (error as { response?: { data?: unknown } }).response?.data;\n\n        if (status === 400) {\n          const validationError = toCamelCase<SystemConfigValidationErrorResponse>(payloadData ?? {});\n          throw new SystemConfigValidationError(\n            parsed.message || validationError.message || '配置校验失败',\n            validationError.issues || [],\n            parsed,\n          );\n        }\n\n        if (status === 409) {\n          const conflict = toCamelCase<SystemConfigConflictResponse>(payloadData ?? {});\n          throw new SystemConfigConflictError(\n            parsed.message || conflict.message || '配置版本冲突',\n            conflict.currentConfigVersion,\n            parsed,\n          );\n        }\n      }\n\n      throw error;\n    }","sourceCodeStart":302,"sourceCodeEnd":338,"githubUrl":"https://github.com/ZhuLinsen/daily_stock_analysis/blob/5159bd72e8373d215492dff122acc9d389e219c9/apps/dsa-web/src/api/systemConfig.ts#L302-L338","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Find bad rows: query trades where quantity <= 0 OR price <= 0 OR price IS NULL for the account and fix or delete them","For transfers/gifts, record a nominal positive price (e.g. cost basis) or model as a buy at the documented cost","Re-write corrected rows through add_trade to get write-time validation","Make the importer reject blank/zero prices instead of coercing to 0"],"exampleFix":"# before\nsvc.add_trade(account_id=1, symbol=\"AAPL\", side=\"buy\", quantity=10, price=0, ...)\n# after\nsvc.add_trade(account_id=1, symbol=\"AAPL\", side=\"buy\", quantity=10, price=185.50, ...)","handlingStrategy":"validation","validationCode":"def stored_trade_values_ok(qty, price):\n    return qty is not None and qty > 0 and price is not None and price > 0","typeGuard":"from numbers import Real\n\ndef is_positive_price(value: Real | None) -> bool:\n    return value is not None and float(value) > 0.0","tryCatchPattern":"try:\n    svc.get_snapshot(account_id=a)\nexcept ValueError as exc:\n    if \"Invalid trade quantity or price\" in str(exc):\n        fix_zero_price_trades(a); svc.get_snapshot(account_id=a)\n    else:\n        raise","preventionTips":["Use a nominal positive price for transfers/gifts, never 0","Reject blank price columns in importers","Audit trades for price <= 0 after bulk loads"],"tags":["portfolio","validation","trade","price","replay","data-corruption"],"backgroundTag":null,"analyzedSha":"5159bd72e8373d215492dff122acc9d389e219c9","analyzedAt":"2026-08-15T01:59:36.292Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}