TheAlgorithms/Python · error · ValueError

principal must be > 0

Error message

principal must be > 0

What it means

Raised by simple_interest() in financial/interest.py when principal <= 0. It is the third and final check, so both days and rate are already valid when it fires. The message text is shared verbatim with the principal checks in compound_interest and apr_interest in the same module.

Source

Thrown at financial/interest.py:38

    >>> simple_interest(10000.0, -0.06, 3)
    Traceback (most recent call last):
        ...
    ValueError: daily_interest_rate must be >= 0
    >>> simple_interest(-10000.0, 0.06, 3)
    Traceback (most recent call last):
        ...
    ValueError: principal must be > 0
    >>> simple_interest(5500.0, 0.01, -5)
    Traceback (most recent call last):
        ...
    ValueError: days_between_payments must be > 0
    """
    if days_between_payments <= 0:
        raise ValueError("days_between_payments must be > 0")
    if daily_interest_rate < 0:
        raise ValueError("daily_interest_rate must be >= 0")
    if principal <= 0:
        raise ValueError("principal must be > 0")
    return principal * daily_interest_rate * days_between_payments


def compound_interest(
    principal: float,
    nominal_annual_interest_rate_percentage: float,
    number_of_compounding_periods: float,
) -> float:
    """
    >>> compound_interest(10000.0, 0.05, 3)
    1576.2500000000014
    >>> compound_interest(10000.0, 0.05, 1)
    500.00000000000045
    >>> compound_interest(0.5, 0.05, 3)
    0.07881250000000006
    >>> compound_interest(10000.0, 0.06, -4)
    Traceback (most recent call last):
        ...

View on GitHub (pinned to f5988cc097)

Solutions

  1. Pass a strictly positive principal amount.
  2. If your ledger stores debts negative, negate at the boundary: `simple_interest(-balance, ...)` when balance < 0.
  3. Validate the full triple (days > 0, rate >= 0, principal > 0) before calling to fail with one clear message.

Example fix

# before
si = simple_interest(-10000.0, 0.06, 3)  # ValueError

# after
si = simple_interest(10000.0, 0.06, 3)
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

try:
    si = simple_interest(principal, daily_rate, days)
except ValueError as exc:
    raise InputError(str(exc)) from exc

Prevention

When it happens

Trigger: simple_interest(-10000.0, 0.06, 3) or principal=0.0; ledger rows where a debit was stored as a negative amount; empty form input coerced to 0.

Common situations: Accounting systems storing liabilities as negative numbers; missing values defaulting to 0 in spreadsheets/CSV; test fixtures with a 0 principal sentinel.

Related errors


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