{"record":{"id":"fc86436bd790f6d9","repo":"HKUDS/Vibe-Trading","slug":"amount-must-be-numeric-got-self-amount-r","errorCode":null,"errorMessage":"amount must be numeric, got {self.amount!r}","messagePattern":"amount must be numeric, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"agent/src/entities/cashflow.py","lineNumber":159,"sourceCode":"    currency: str\n    metadata: Mapping[str, Any] = field(default_factory=dict)\n\n    def __post_init__(self) -> None:\n        \"\"\"Normalize every field and enforce the sign convention.\n\n        Raises:\n            ValueError: If the date is unsupported, the amount is not finite,\n                the currency or kind is blank, or the amount's sign contradicts\n                a canonical kind in ``KIND_DIRECTION``.\n        \"\"\"\n        object.__setattr__(self, \"date\", normalize_date(self.date))\n        object.__setattr__(self, \"kind\", normalize_kind(self.kind))\n        object.__setattr__(self, \"currency\", normalize_currency(self.currency))\n\n        try:\n            amount = float(self.amount)\n        except (TypeError, ValueError) as exc:\n            raise ValueError(\n                f\"amount must be numeric, got {self.amount!r}\"\n            ) from exc\n        if not math.isfinite(amount):\n            raise ValueError(\n                f\"amount must be a finite number, got {self.amount!r}; a missing \"\n                \"value must be fixed at the source, not carried as NaN\"\n            )\n        object.__setattr__(self, \"amount\", amount)\n\n        required_sign = KIND_DIRECTION.get(self.kind)\n        if required_sign is not None and amount != 0.0:\n            if (amount > 0) != (required_sign > 0):\n                direction = \"positive (cash in)\" if required_sign > 0 else \"negative (cash out)\"\n                raise ValueError(\n                    f\"kind={self.kind!r} must have a {direction} amount under the \"\n                    f\"holder-perspective sign convention, got {amount!r}. Flip the \"\n                    \"sign, or use a distinct kind if this flow is genuinely \"\n                    \"two-directional (e.g. 'recallable_distribution').\"","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/entities/cashflow.py#L141-L177","documentation":"CashFlow.__post_init__ coerces the amount field to float; if float(self.amount) raises TypeError or ValueError, the conversion failure is re-raised as a ValueError with the offending repr. The library requires every cash flow's amount to be a number so arithmetic (sums, sign checks, FX translation) is well-defined.","triggerScenarios":"Constructing CashFlow with a non-numeric amount: CashFlow(amount='abc', ...), CashFlow(amount=None, ...), or a string like '1,234.56' that float() cannot parse.","commonSituations":"Rows loaded from CSV/Excel where the amount column has thousands separators, currency symbols, empty cells, or stray text; dataclass defaults left as None; pandas object-dtype values passed through unconverted.","solutions":["Coerce/parse the amount to a float before constructing CashFlow (strip separators/currency symbols, treat empty strings as missing data to fix upstream)","Validate the source column at ingest time (e.g. a parse step in your loader) instead of at entity construction","If the value is genuinely missing, fix or drop the row at the source rather than passing a placeholder string"],"exampleFix":"// before\nCashFlow(date=d, kind='dividend', amount='1,234.56', currency='USD')\n# after\nCashFlow(date=d, kind='dividend', amount=1234.56, currency='USD')","handlingStrategy":"validation","validationCode":"def to_amount(raw):\n    try:\n        value = float(raw)\n    except (TypeError, ValueError):\n        raise ValueError(f'unparseable amount: {raw!r}') from None\n    return value\n\namounts_ok = all(isinstance(to_amount(r.get('amount')), float) for r in rows)","typeGuard":"def is_numeric_amount(v) -> bool:\n    return isinstance(v, (int, float)) and not isinstance(v, bool)","tryCatchPattern":"try:\n    flow = CashFlow(amount=raw, ...)\nexcept ValueError as e:\n    if 'amount must be numeric' in str(e):\n        # log the row, skip or repair\n        ...","preventionTips":["Parse/normalize numeric columns before constructing entities","Reject or quarantine rows with empty/alpha amounts at ingest","Keep DataFrame dtypes numeric (pd.to_numeric with errors='raise') before .to_dict()"],"tags":["python","cashflow","type-validation","dataclass"],"backgroundTag":"numeric-field-parse-failed","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}