TheAlgorithms/Python · error · Exception
Years to repay must be an integer > 0
Error message
Years to repay must be an integer > 0
What it means
Raised by equated_monthly_installments() in financial/equated_monthly_installments.py when years_to_repay <= 0 OR years_to_repay is not an int. The tenure must be a whole number of years because it is multiplied by 12 to get the payment count; floats like 2.5 are rejected even though they are positive. It is the third and last check, so principal and rate are already valid when it fires.
Source
Thrown at financial/equated_monthly_installments.py:42
>>> equated_monthly_installments(0, 0.12, 3)
Traceback (most recent call last):
...
Exception: Principal borrowed must be > 0
>>> equated_monthly_installments(25000, -1, 3)
Traceback (most recent call last):
...
Exception: Rate of interest must be >= 0
>>> equated_monthly_installments(25000, 0.12, 0)
Traceback (most recent call last):
...
Exception: Years to repay must be an integer > 0
"""
if principal <= 0:
raise Exception("Principal borrowed must be > 0")
if rate_per_annum < 0:
raise Exception("Rate of interest must be >= 0")
if years_to_repay <= 0 or not isinstance(years_to_repay, int):
raise Exception("Years to repay must be an integer > 0")
# Yearly rate is divided by 12 to get monthly rate
rate_per_month = rate_per_annum / 12
# Years to repay is multiplied by 12 to get number of payments as payment is monthly
number_of_payments = years_to_repay * 12
return (
principal
* rate_per_month
* (1 + rate_per_month) ** number_of_payments
/ ((1 + rate_per_month) ** number_of_payments - 1)
)
if __name__ == "__main__":
import doctest
View on GitHub (pinned to f5988cc097)
Solutions
- Pass an int: years_to_repay=3, not 3.0 or '3'.
- Coerce deliberately: `years = int(round(months / 12))` — but verify rounding half-year tenures is acceptable for your use case.
- For fractional years, call with int years and handle the remainder separately, or use a formula that accepts months directly.
Example fix
# before emi = equated_monthly_installments(25000, 0.12, 36 / 12) # 3.0 is not int -> Exception # after emi = equated_monthly_installments(25000, 0.12, int(36 / 12)) # 3
Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(years_to_repay, int) or years_to_repay <= 0:
# bool is an int subclass; exclude it explicitly if needed
raise LoanInputError("years_to_repay must be an int > 0") Type guard
def valid_years(y) -> bool:
return isinstance(y, int) and not isinstance(y, bool) and y > 0 Try / catch
try:
emi = equated_monthly_installments(principal, rate, int(years_to_repay))
except (TypeError, Exception) as exc:
raise LoanInputError(str(exc)) from exc Prevention
- Coerce tenures with int(round(...)) after any months->years division.
- Parse CLI tenure with type=int so strings never reach the call.
- JSON numbers deserialize as float — convert before calling.
When it happens
Trigger: equated_monthly_installments(25000, 0.12, 0); passing 2.5 years, '3' (string), or 3.0 (float) — 3.0 fails the isinstance(int) test; tenures computed as float divisions like 36/12 producing 3.0.
Common situations: JSON/YAML configs where the tenure is parsed as 3.0; converting months to years with division and forgetting to int(); user input arriving as a string from a CLI.
Related errors
- Principal borrowed must be > 0
- Rate of interest must be >= 0
- window_size must be > 0
- days_between_payments must be > 0
- daily_interest_rate must be >= 0
AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14).
Data as JSON: /api/errors/3ced6cd62c540f3f.
Report an issue: GitHub.