{"record":{"id":"d539d5f5112c21d5","repo":"TheAlgorithms/Python","slug":"first-rotor-position-is-not-within-range-of-1-26","errorCode":null,"errorMessage":"First rotor position is not within range of 1..26 ({rotorpos1}","messagePattern":"First rotor position is not within range of 1\\.\\.26 \\((.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ciphers/enigma_machine2.py","lineNumber":100,"sourceCode":"'ZJXESIUQLHAVRMDOYGTNFWPBKC'), \\\n{'P': 'O', 'O': 'P', 'L': 'A', 'A': 'L', 'N': 'D', 'D': 'N'})\n\n    :param rotpos: rotor_positon\n    :param rotsel: rotor_selection\n    :param pb: plugb -> validated and transformed\n    :return: (`rotpos`, `rotsel`, `pb`)\n    \"\"\"\n    # Checks if there are 3 unique rotors\n\n    if (unique_rotsel := len(set(rotsel))) < 3:\n        msg = f\"Please use 3 unique rotors (not {unique_rotsel})\"\n        raise Exception(msg)\n\n    # Checks if rotor positions are valid\n    rotorpos1, rotorpos2, rotorpos3 = rotpos\n    if not 0 < rotorpos1 <= len(abc):\n        msg = f\"First rotor position is not within range of 1..26 ({rotorpos1}\"\n        raise ValueError(msg)\n    if not 0 < rotorpos2 <= len(abc):\n        msg = f\"Second rotor position is not within range of 1..26 ({rotorpos2})\"\n        raise ValueError(msg)\n    if not 0 < rotorpos3 <= len(abc):\n        msg = f\"Third rotor position is not within range of 1..26 ({rotorpos3})\"\n        raise ValueError(msg)\n\n    # Validates string and returns dict\n    pbdict = _plugboard(pb)\n\n    return rotpos, rotsel, pbdict\n\n\ndef _plugboard(pbstring: str) -> dict[str, str]:\n    \"\"\"\n    https://en.wikipedia.org/wiki/Enigma_machine#Plugboard\n\n    >>> _plugboard('PICTURES')","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/TheAlgorithms/Python/blob/f5988cc09713315817df6a7e327e258013a94440/ciphers/enigma_machine2.py#L82-L118","documentation":"Raised by the Enigma machine validator when the FIRST rotor position is outside 1..26 (len(abc)). Rotor positions are 1-based in this API, so 0, negatives, and anything above 26 fail. Minor cosmetic bug: the f-string message is missing its closing parenthesis.","triggerScenarios":"Calling with rotpos=(0, 1, 1), (-3, 5, 5), or (27, 1, 1); converting 0-based positions from another API without adding 1.","commonSituations":"Index math off-by-one after porting code that used 0-based rotor settings; parsing user input without range checking; random.randint(0, 26) instead of randint(1, 26).","solutions":["Use positions in 1..26 inclusive, e.g. rotpos=(1, 1, 1)","Clamp/convert 0-based values: rotpos = tuple(p + 1 for p in zero_based)","Validate all three positions with all(0 < p <= 26 for p in rotpos) before the call"],"exampleFix":"# before\nrotpos = (0, 13, 26)  # first rotor invalid\n\n# after\nrotpos = (1, 13, 26)","handlingStrategy":"validation","validationCode":"rotpos1, rotpos2, rotpos3 = rotpos\nassert 0 < rotpos1 <= 26, \"rotor positions are 1-based, 1..26\"","typeGuard":"def valid_rotor_positions(rotpos) -> bool:\n    return len(rotpos) == 3 and all(0 < p <= 26 for p in rotpos)","tryCatchPattern":"try:\n    settings = validate_and_transform(rotpos, rotsel, pb)\nexcept ValueError as exc:\n    if \"rotor position\" in str(exc):\n        rotpos = tuple(min(max(p, 1), 26) for p in rotpos)\n    else:\n        raise","preventionTips":["Remember positions are 1-based (1..26), not 0-based","Validate the whole tuple with all(0 < p <= 26 for p in rotpos)","Use random.randint(1, 26) when generating settings"],"tags":["enigma","rotor-position","off-by-one","validation"],"backgroundTag":null,"analyzedSha":"f5988cc09713315817df6a7e327e258013a94440","analyzedAt":"2026-08-14T17:30:07.041Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}