HKUDS/Vibe-Trading · error · ValueError
FCFFYear(year={self.year}).nopat={self.nopat!r} does not mat
Error message
FCFFYear(year={self.year}).nopat={self.nopat!r} does not match ebit * (1 - tax_rate) = {expected_nopat!r} What it means
FCFFYear.__post_init__ recomputes nopat = ebit * (1 - tax_rate) and raises ValueError if the stored nopat differs beyond _RECONCILIATION_TOLERANCE. This is an internal reconciliation check preventing inconsistent forecast rows.
Source
Thrown at agent/src/quantlib/valuation/dcf.py:562
depreciation_amortization: float
capex: float
delta_nwc: float
fcff: float
def __post_init__(self) -> None:
"""Re-check the NOPAT and FCFF arithmetic.
Raises:
ValueError: If ``nopat`` or ``fcff`` do not match their formulas,
or ``year`` is not a positive integer.
"""
if self.year < 1:
raise ValueError(f"FCFFYear.year must be >= 1, got {self.year!r}")
expected_nopat = self.ebit * (1.0 - self.tax_rate)
if not math.isclose(
self.nopat, expected_nopat, rel_tol=_RECONCILIATION_TOLERANCE, abs_tol=1e-9
):
raise ValueError(
f"FCFFYear(year={self.year}).nopat={self.nopat!r} does not match "
f"ebit * (1 - tax_rate) = {expected_nopat!r}"
)
expected_fcff = (
self.nopat + self.depreciation_amortization - self.capex - self.delta_nwc
)
if not math.isclose(
self.fcff, expected_fcff, rel_tol=_RECONCILIATION_TOLERANCE, abs_tol=1e-9
):
raise ValueError(
f"FCFFYear(year={self.year}).fcff={self.fcff!r} does not match the "
f"bridge total {expected_fcff!r}"
)
def fcff_bridge(
*,
ebit: Sequence[float],View on GitHub (pinned to 80ffdda44c)
Solutions
- Compute nopat = ebit * (1 - tax_rate) in the caller and pass the unrounded result
- Or build rows via fcff_bridge(), which derives nopat internally
- Round inputs (ebit, tax_rate) before the call rather than rounding nopat after
Example fix
# before FCFFYear(year=1, ebit=100.0, tax_rate=0.25, nopat=75.1, ...) # after FCFFYear(year=1, ebit=100.0, tax_rate=0.25, nopat=100.0*(1-0.25), ...)
Defensive patterns
Strategy: validation
Validate before calling
nopat = ebit * (1.0 - tax_rate) FCFFYear(year=1, ebit=ebit, tax_rate=tax_rate, nopat=nopat, ...)
Try / catch
try:
FCFFYear(...)
except ValueError as e:
if 'nopat' in str(e):
row['nopat'] = row['ebit'] * (1 - row['tax_rate'])
raise Prevention
- Derive nopat, never enter it independently
- Round ebit/tax_rate upstream, not nopat downstream
- Use fcff_bridge() for imported spreadsheets
When it happens
Trigger: Constructing FCFFYear with a hand-computed or rounded nopat (e.g. 60 instead of 60.0*0.75=45), or rounding nopat to fewer decimals than the tolerance allows.
Common situations: Importing forecasts from spreadsheets where nopat was independently entered/rounded rather than derived; unit tests building fixtures with approximate numbers.
Related errors
- FCFFYear(year={self.year}).fcff={self.fcff!r} does not match
- WACCResult.wacc={self.wacc!r} does not match the weighted bl
- FCFFYear.year must be >= 1, got {self.year!r}
- fcff_bridge: tax_rate must be within [0, 1], got {tax_rate!r
- fcff_bridge: ebit forecast is empty; at least one projection
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/e44090c2eee87892.
Report an issue: GitHub.