ZhuLinsen/daily_stock_analysis · error · DuplicateTaskError
股票 ${stockCode} 正在分析中
Error message
股票 ${stockCode} 正在分析中 What it means
Raised during quantity replay (portfolio_service.py:757) when a trade event has quantity <= 0 (null coerces to 0.0). The replay's ledger semantics require positive quantities, so a corrupt or zero-quantity trade row aborts the whole position computation with validation_error.
Source
Thrown at apps/dsa-web/src/api/analysis.ts:94
const response = await apiClient.post<Record<string, unknown>>(
'/api/v1/analysis/analyze',
requestData,
{
// Allow 202 accepted responses in addition to standard success codes.
validateStatus: (status) => status === 200 || status === 202 || status === 409,
}
);
// Handle duplicate submission compatibility.
if (response.status === 409) {
const errorData = toCamelCase<{
error: string;
message: string;
stockCode: string;
existingTaskId: string;
}>(response.data);
throw new DuplicateTaskError(errorData.stockCode, errorData.existingTaskId, errorData.message);
}
return toCamelCase<AnalyzeAsyncResponse>(response.data);
},
/**
* Trigger market review in background mode.
*/
triggerMarketReview: async (data: MarketReviewRequest = {}): Promise<MarketReviewAccepted> => {
const response = await apiClient.post<Record<string, unknown>>(
'/api/v1/analysis/market-review',
{
send_notification: data.sendNotification ?? true,
report_language: data.reportLanguage,
...(data.regions !== undefined && { region: serializeMarketReviewRegions(data.regions) }),
},
{
validateStatus: (status) => status === 202 || status === 409,View on GitHub (pinned to 5159bd72e8)
Solutions
- Locate the offending trade: query trades for the symbol where quantity IS NULL or <= 0 and fix or delete the row
- Re-insert valid trades through add_trade, which validates quantity at write time
- Fix the importer to fail on blank quantity instead of defaulting to 0
- Add a DB-level CHECK (quantity > 0) or a periodic audit query
Example fix
# before svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=0, price=100.0, ...) # after svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=10, price=100.0, ...)
Defensive patterns
Strategy: validation
Validate before calling
def trade_qty_ok(qty):
return qty is not None and qty > 0 Type guard
from numbers import Real
def is_positive_quantity(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" in str(exc):
repair_or_delete_bad_trade_rows(a); svc.get_snapshot(account_id=a)
else:
raise Prevention
- Never insert trade rows directly into the DB
- Reject blank quantity in importers instead of defaulting to 0
- Periodically audit trades for quantity <= 0 or NULL
When it happens
Trigger: A trades row with quantity = 0, negative, or NULL reaching the replay; test rows inserted directly into the DB; importer writing 0 when the source field is missing; float('-inf')/NaN coerced through float() to a non-positive value.
Common situations: Direct database seeding in dev/test that skips service validation; CSV import with a blank quantity column parsed as 0; fee-only rows mistakenly imported as trades with zero quantity; refactors of the write path that forgot the positivity check.
Related errors
AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15).
Data as JSON: /api/errors/608764d6c3a92488.
Report an issue: GitHub.