{"record":{"id":"8e859f257272446d","repo":"TheAlgorithms/Python","slug":"limit-for-the-catalan-sequence-must-be-0","errorCode":null,"errorMessage":"Limit for the Catalan sequence must be ≥ 0","messagePattern":"Limit for the Catalan sequence must be ≥ 0","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"dynamic_programming/catalan_numbers.py","lineNumber":43,"sourceCode":" *  [1] https://brilliant.org/wiki/catalan-numbers/\n *  [2] https://en.wikipedia.org/wiki/Catalan_number\n\"\"\"\n\n\ndef catalan_numbers(upper_limit: int) -> \"list[int]\":\n    \"\"\"\n    Return a list of the Catalan number sequence from 0 through `upper_limit`.\n\n    >>> catalan_numbers(5)\n    [1, 1, 2, 5, 14, 42]\n    >>> catalan_numbers(2)\n    [1, 1, 2]\n    >>> catalan_numbers(-1)\n    Traceback (most recent call last):\n    ValueError: Limit for the Catalan sequence must be ≥ 0\n    \"\"\"\n    if upper_limit < 0:\n        raise ValueError(\"Limit for the Catalan sequence must be ≥ 0\")\n\n    catalan_list = [0] * (upper_limit + 1)\n\n    # Base case: C(0) = C(1) = 1\n    catalan_list[0] = 1\n    if upper_limit > 0:\n        catalan_list[1] = 1\n\n    # Recurrence relation: C(i) = sum(C(j).C(i-j-1)), from j = 0 to i\n    for i in range(2, upper_limit + 1):\n        for j in range(i):\n            catalan_list[i] += catalan_list[j] * catalan_list[i - j - 1]\n\n    return catalan_list\n\n\nif __name__ == \"__main__\":\n    print(\"\\n********* Catalan Numbers Using Dynamic Programming ************\\n\")","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/dynamic_programming/catalan_numbers.py#L25-L61","documentation":"Raised by catalan_numbers(upper_limit) when upper_limit is negative. The function builds a list of length upper_limit + 1, so any negative limit other than the guard would create an empty or invalid list; a negative index would crash later. ValueError is thrown immediately with a clear 'must be >= 0' message (documented in the doctest for -1).","triggerScenarios":"catalan_numbers(-1) or any negative integer argument, e.g. when upper_limit comes from user input or len(data) - 1 on an empty dataset. Floats like -0.5 also compare negative and raise.","commonSituations":"Computing a range bound from an empty collection (len([]) - 1 == -1); CLI arguments parsed without validation; off-by-one when converting an inclusive/exclusive limit.","solutions":["Check the bound before calling: n = max(0, n) only if clamping is acceptable, otherwise surface the error to the caller.","Fix the source of the negative value — usually an empty input list or an off-by-one in limit computation.","Validate user-supplied limits at the CLI/config boundary with int(x); x >= 0 checks."],"exampleFix":"# before\nlimit = len(values) - 1  # -1 when values is empty\ncats = catalan_numbers(limit)\n\n# after\nif values:\n    cats = catalan_numbers(len(values) - 1)\nelse:\n    cats = []","handlingStrategy":"validation","validationCode":"upper_limit = int(upper_limit)\nif upper_limit < 0:\n    raise ValueError('upper_limit must be >= 0')\ncats = catalan_numbers(upper_limit)","typeGuard":"def is_non_negative_int(value: object) -> bool:\n    return isinstance(value, int) and value >= 0","tryCatchPattern":"try:\n    cats = catalan_numbers(limit)\nexcept ValueError as exc:\n    if 'must be' in str(exc):\n        cats = []  # or re-raise with domain context\n    else:\n        raise","preventionTips":["Never derive sequence limits from len(collection) - 1 without handling empty collections.","Validate numeric bounds at the CLI/config boundary.","Fuzz test numeric helpers with -1, 0, and 1 to catch bound bugs early."],"tags":["python","input-validation","dynamic-programming","math"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}