Nested Exception Handling Statements in Python

Learn nested exception handling in Python with age validation, retry prompts, while loops, Boolean flags, ValueError, and clearer break/continue patterns.

When a Python program reads data from a user, the input may not have the expected form. For example, input() always returns a string, so converting that string with int() can fail if the user enters letters.

This lesson combines exception handling with a while loop so a program can report invalid input and decide whether to try again instead of terminating.

Nested exception handling statements means using exception-handling operations as part of a larger control-flow structure, such as a loop containing one or more input-validation steps.

Prerequisites and Key Terms

  • Exception: A runtime event or error that interrupts normal program flow unless it is handled.
  • Exception handling: Code that catches and responds to anticipated runtime errors.
  • try block: The block containing code that may raise an exception.
  • except block: The block that runs when a matching exception occurs.
  • ValueError: The exception commonly raised when int() receives text that cannot be converted to an integer.
  • input(): A function that reads user input as a string.
  • int(): A conversion function that turns a valid numeric string into an integer.
  • while loop: A loop that repeats while its condition remains true.
  • Boolean flag: A True or False variable used to control whether a loop continues.
  • Conditional statement: An if/else decision that selects different actions based on a condition.

Why Put Exception Handling Inside a Loop?

A basic input program might stop immediately when conversion fails:

age = int(input("Enter your age: "))
print(f"Your age is {age}.")

If the user enters twenty, int() raises ValueError. Since there is no matching handler, the program terminates.

Exception handling lets the program recover:

try:
    age = int(input("Enter your age: "))
    print(f"Your age is {age}.")
except ValueError:
    print("Please enter your age as a whole number.")

This handles the error and notifies the user. It does not, by itself, decide whether another attempt should happen. Retry behavior is a separate control-flow decision, usually implemented with a loop and a condition.

Retrying with a Boolean Control Variable

A Boolean flag can control a loop. The flag starts as True, so the first attempt runs. Later code changes it to False when the interaction should end.

keep_trying = True

while keep_trying:
    print("This attempt is running.")
    keep_trying = False

The while keep_trying condition is evaluated before each iteration. When the flag becomes False, the loop stops before another iteration begins.

Age Input with a Retry Prompt

The following example places age conversion in one try block and places the retry-command conversion in a separate try block. The retry question appears only after an invalid age, which avoids asking a successful user whether to restart.

keep_trying = True

while keep_trying:
    try:
        age = int(input("Enter your age: "))
        print(f"You entered age {age}.")
        keep_trying = False
    except ValueError:
        print("Invalid age: please enter a whole number.")

        try:
            retry = int(input("Enter 0 to try again, or another number to exit: "))
        except ValueError:
            print("The retry command was not a number. Exiting.")
            keep_trying = False
        else:
            if retry == 0:
                keep_trying = True
            else:
                print("Exiting without another attempt.")
                keep_trying = False

The outer control structure is the while loop. Inside it, the first try/except handles age conversion. If age conversion fails, a second input step runs. That second step has its own try/except because the retry response also needs conversion.

What Each Part Does

  • keep_trying = True permits the first loop iteration.
  • int(input("Enter your age: ")) reads text and attempts integer conversion.
  • except ValueError catches non-numeric age input.
  • The correction message tells the user what form is required.
  • The retry prompt asks for a numeric command.
  • A retry value of 0 means start another age attempt.
  • Another valid integer means exit.
  • A non-numeric retry response raises another ValueError, which is handled by the inner handler and causes an exit.

Input Outcomes and Program Behavior

Input stageUser inputConversion resultException handledMessage or actionLoop outcome
Age prompt42age becomes 42NonePrint the accepted ageFlag becomes False; stop
Age promptabcConversion failsValueErrorAsk for a whole number, then show retry promptDepends on retry response
Retry prompt0retry becomes 0NoneChoose restartNext iteration begins
Retry prompt1retry becomes 1NonePrint exit messageFlag becomes False; stop
Retry promptagainConversion failsValueErrorPrint an exit-oriented messageFlag becomes False; stop

Choosing the Exception Type

Use the narrowest exception type that describes the failure you expect. Since invalid text passed to int() raises ValueError, this is the appropriate handler:

try:
    retry = int(input("Enter 0 to retry: "))
except ValueError:
    print("Please use a number.")
ClauseWhat it catchesAppropriate useCaution
except ValueErrorValue-related failures such as invalid integer textExpected failures from int()It does not catch unrelated exception types
Bare exceptNearly every exception, including many unexpected onesRare cases where broad interception is deliberately requiredIt can hide programming mistakes and interrupt signals
except ExceptionMost ordinary runtime exceptionsControlled top-level fallback or logging when broad handling is intentionalStill too broad for a known numeric-conversion failure

A bare except may appear in simple older examples, but it is usually a poor choice here. Replace it with except ValueError for invalid numeric retry commands. If several specific failures are expected, handle those intended exception types explicitly.

Control-Flow Walkthroughs

Non-numeric Age Followed by a Non-numeric Retry Response

  1. The loop condition is checked. keep_trying is True, so the iteration starts.
  2. The age try block calls input() and then int().
  3. If the user enters old, conversion raises ValueError.
  4. Python skips the rest of that try block and runs its except ValueError block.
  5. The program prints the correction message and asks for a retry command.
  6. If the user enters maybe, the inner int() call raises ValueError.
  7. The inner except ValueError prints an exit message and sets the flag to False.
  8. The loop reaches its end. Its next condition check is false, so no new age attempt runs.

Non-numeric Age Followed by 0

  1. The age conversion raises ValueError, so the outer age handler runs.
  2. The retry prompt receives 0; conversion succeeds.
  3. The if retry == 0 condition is true.
  4. The program leaves the handler with keep_trying still true.
  5. The loop checks its condition and begins another iteration.
  6. The user can now enter a valid age, such as 27.
  7. The age conversion succeeds, the valid-age message prints, and the flag becomes False.
  8. The next loop check ends the interaction.

Valid Age Input

  1. The age try block converts the input successfully.
  2. No except block runs because no exception occurred.
  3. The success message prints and the flag is set to False.
  4. The retry prompt is not reached because it is inside the age except block.
  5. The loop ends on its next condition check.

Separating Validation from Retry Decisions

Age validation and retry selection are different decisions. Keeping them in separate blocks makes the program easier to read:

  • The age try block answers: “Can this input be converted to an integer?”
  • The age except block answers: “What should happen when conversion fails?”
  • The retry try block answers: “Is the retry command itself a valid integer?”
  • The retry if statement answers: “Does the valid command mean restart or exit?”

Do not place a retry prompt outside the branch where it belongs without deciding what it should mean after a successful age. Otherwise, users may be asked whether to restart even though the age was valid.

A Clearer Version with continue and break

A Boolean flag is useful for learning loop state, but explicit loop control can make the intended exits clearer. continue immediately starts the next iteration, while break ends the loop.

while True:
    try:
        age = int(input("Enter your age: "))
    except ValueError:
        print("Invalid age: please enter a whole number.")

        try:
            retry = int(input("Enter 0 to try again, or another number to exit: "))
        except ValueError:
            print("The retry command was not a number. Exiting.")
            break

        if retry == 0:
            continue

        print("Exiting without another attempt.")
        break
    else:
        print(f"You entered age {age}.")
        break

Here, continue is reached only when the retry value is 0. The loop returns directly to its condition check, which is always true for while True, and begins another attempt. Every exit path uses break.

Common Problems and Fixes

The Program Stops When Letters Are Entered for an Age

The int() conversion is probably outside a try block, or the code does not catch ValueError. Put the conversion inside try and display a validation message in except ValueError.

The Loop Keeps Running After the User Chooses to Exit

The Boolean flag may never be changed to False, or the exit branch may be missing break. Check every exit path. With the Boolean design, update the flag; with the clearer alternative, use break.

An Invalid Retry Response Behaves Unexpectedly

The retry conversion may be unhandled, or a broad exception clause may obscure the actual problem. Catch ValueError specifically and define the behavior, such as printing an exit message and stopping.

A Bare except Hides a Programming Mistake

A bare handler can catch errors unrelated to user input, making debugging difficult. Use the narrowest expected type, normally ValueError for failed integer conversion.

The User Is Asked to Restart After a Valid Age

The retry prompt is likely outside the invalid-input branch. If retry confirmation should occur only after an error, put the prompt inside the age except block or use the separate validation structure shown above.

Exam-Relevant Notes

  • input() returns a string, even when the user types digits.
  • int("25") succeeds, but int("twenty-five") raises ValueError.
  • Only a matching except block runs when an exception occurs.
  • If no exception occurs, the matching except block is skipped.
  • An if statement can choose between retry and exit after a successful retry-command conversion.
  • A loop condition controls whether another iteration begins; handling an exception does not automatically repeat the loop.
  • Specific exception handlers are safer and clearer than bare except clauses.
  • Indentation determines whether the retry prompt runs only after an invalid age or after every age attempt.

Summary

Nested exception handling combines a loop, one or more try/except blocks, and conditional decisions. Protect numeric conversions with except ValueError, explain invalid input clearly, and use a Boolean flag or explicit break/continue statements to control retries. Treat error handling, user notification, and retry selection as separate responsibilities so the resulting input flow remains predictable.