TheAlgorithms/Python · error · ValueError
nominal_annual_percentage_rate must be >= 0
Error message
nominal_annual_percentage_rate must be >= 0
What it means
Raised by apr_interest() when nominal_annual_percentage_rate < 0. A negative APR has no financial meaning for this compounding formula (it would represent a guaranteed-loss product the function does not model), so it is rejected before delegation to compound_interest. The check allows exactly 0 (simple no-growth case).
Source
Thrown at financial/interest.py:108
>>> apr_interest(0.5, 0.05, 3)
0.08091115361317736
>>> apr_interest(10000.0, 0.06, -4)
Traceback (most recent call last):
...
ValueError: number_of_years must be > 0
>>> apr_interest(10000.0, -3.5, 3.0)
Traceback (most recent call last):
...
ValueError: nominal_annual_percentage_rate must be >= 0
>>> apr_interest(-5500.0, 0.01, 5)
Traceback (most recent call last):
...
ValueError: principal must be > 0
"""
if number_of_years <= 0:
raise ValueError("number_of_years must be > 0")
if nominal_annual_percentage_rate < 0:
raise ValueError("nominal_annual_percentage_rate must be >= 0")
if principal <= 0:
raise ValueError("principal must be > 0")
return compound_interest(
principal, nominal_annual_percentage_rate / 365, number_of_years * 365
)
if __name__ == "__main__":
import doctest
doctest.testmod()
View on GitHub (pinned to f5988cc097)
Solutions
- Pass a rate >= 0; use 0 for a zero-interest instrument.
- Check the data source for sign conventions (e.g. some APIs report yield changes, not levels, as negative).
- If you need negative-growth modelling, apr_interest does not support it — compute it with compound_interest directly after your own validation.
Example fix
# before
apr_interest(10000.0, latest_rate, 3) # latest_rate == -3.5 from feed
# after
rate = max(0.0, latest_rate) if clamped else latest_rate
if rate < 0:
raise ValueError(f'unsupported negative APR: {rate}')
apr_interest(10000.0, rate, 3) Defensive patterns
Strategy: validation
Validate before calling
if apr < 0:
raise ValueError(f'APR cannot be negative, got {apr}')
apr_interest(principal, apr, years) Try / catch
try:
value = apr_interest(p, r, y)
except ValueError as exc:
if 'nominal_annual_percentage_rate' in str(exc):
# bad rate data, not a code bug
log.warning('skipping negative APR %s', r); return None
raise Prevention
- Never use -1 as a 'missing rate' sentinel when calling this function.
- Pin down percentage-vs-fraction units once at the ingestion layer.
When it happens
Trigger: Calling apr_interest(10000.0, -3.5, 3.0) or any call where the rate argument is negative. Only reached when number_of_years > 0, since years is validated first.
Common situations: Reading rates from feeds that encode decreases as negatives, mixing up percentage (3.5) and fractional (0.035) conventions with a sign error, or passing a placeholder -1 sentinel meaning 'no rate'.
Related errors
- number_of_years must be > 0
- Discount rate cannot be negative
- Cash flows list cannot be empty
- Window size must be a positive integer
- Useful years cannot be less than 1
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/31e86375ff7fe76f.
Report an issue: GitHub.