{"record":{"id":"3ced6cd62c540f3f","repo":"TheAlgorithms/Python","slug":"years-to-repay-must-be-an-integer-0","errorCode":null,"errorMessage":"Years to repay must be an integer > 0","messagePattern":"Years to repay must be an integer > 0","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"financial/equated_monthly_installments.py","lineNumber":42,"sourceCode":"    >>> equated_monthly_installments(0, 0.12, 3)\n    Traceback (most recent call last):\n        ...\n    Exception: Principal borrowed must be > 0\n    >>> equated_monthly_installments(25000, -1, 3)\n    Traceback (most recent call last):\n        ...\n    Exception: Rate of interest must be >= 0\n    >>> equated_monthly_installments(25000, 0.12, 0)\n    Traceback (most recent call last):\n        ...\n    Exception: Years to repay must be an integer > 0\n    \"\"\"\n    if principal <= 0:\n        raise Exception(\"Principal borrowed must be > 0\")\n    if rate_per_annum < 0:\n        raise Exception(\"Rate of interest must be >= 0\")\n    if years_to_repay <= 0 or not isinstance(years_to_repay, int):\n        raise Exception(\"Years to repay must be an integer > 0\")\n\n    # Yearly rate is divided by 12 to get monthly rate\n    rate_per_month = rate_per_annum / 12\n\n    # Years to repay is multiplied by 12 to get number of payments as payment is monthly\n    number_of_payments = years_to_repay * 12\n\n    return (\n        principal\n        * rate_per_month\n        * (1 + rate_per_month) ** number_of_payments\n        / ((1 + rate_per_month) ** number_of_payments - 1)\n    )\n\n\nif __name__ == \"__main__\":\n    import doctest\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/financial/equated_monthly_installments.py#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nemi = equated_monthly_installments(25000, 0.12, 36 / 12)  # 3.0 is not int -> Exception\n\n# after\nemi = equated_monthly_installments(25000, 0.12, int(36 / 12))  # 3","handlingStrategy":"type-guard","validationCode":"if not isinstance(years_to_repay, int) or years_to_repay <= 0:\n    # bool is an int subclass; exclude it explicitly if needed\n    raise LoanInputError(\"years_to_repay must be an int > 0\")","typeGuard":"def valid_years(y) -> bool:\n    return isinstance(y, int) and not isinstance(y, bool) and y > 0","tryCatchPattern":"try:\n    emi = equated_monthly_installments(principal, rate, int(years_to_repay))\nexcept (TypeError, Exception) as exc:\n    raise LoanInputError(str(exc)) from exc","preventionTips":["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."],"tags":["finance","emi","type-check","validation"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}