TheAlgorithms/Python · error · Exception

Principal borrowed must be > 0

Error message

Principal borrowed must be > 0

What it means

Raised by equated_monthly_installments() in financial/equated_monthly_installments.py when principal <= 0. The EMI formula multiplies principal into the annuity factor, so a non-positive loan amount is meaningless; this is the first of three sequential input checks (principal, then rate, then years). Note the function raises bare Exception, not ValueError — so a `except ValueError` handler will not catch it.

Source

Thrown at financial/equated_monthly_installments.py:38

    >>> equated_monthly_installments(25000, 0.12, 3)
    830.3577453212793
    >>> equated_monthly_installments(25000, 0.12, 10)
    358.67737100646826
    >>> 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)
    )

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass a strictly positive principal in the loan's currency units.
  2. Validate at the input boundary (form/parser): require principal > 0 before calling.
  3. When catching, use `except Exception` (or a broad catch) because this library raises bare Exception, unlike its ValueError-based siblings.

Example fix

# before
emi = equated_monthly_installments(0, 0.12, 3)  # Exception

# after
if principal > 0:
    emi = equated_monthly_installments(principal, 0.12, 3)
Defensive patterns

Strategy: validation

Validate before calling

if principal <= 0:
    raise LoanInputError("principal must be > 0")

Type guard

def valid_principal(p) -> bool:
    return isinstance(p, (int, float)) and p > 0

Try / catch

# NOTE: this function raises bare Exception, not ValueError
try:
    emi = equated_monthly_installments(principal, rate, years)
except Exception as exc:  # intentional: matches the library's bare raise
    raise LoanInputError(str(exc)) from exc

Prevention

When it happens

Trigger: equated_monthly_installments(-25000, 0.12, 3) or principal=0; amounts parsed from user input where an empty string became 0; loans denominated in subunits (paise/cents) accidentally divided down to 0.

Common situations: Form fields defaulting to 0; currency conversions that floor small values to 0; test fixtures using 0 as a 'no loan' sentinel.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/35a03278a24e4bf2. Report an issue: GitHub.