Skip to main content

Context-Aware Error Handling

Typer provides a robust mechanism for accessing the execution state of a CLI application through the Context and CallbackParam classes. These classes allow developers to implement sophisticated validation logic and error handling that is aware of the command-line environment, such as which subcommand was invoked or which specific parameter triggered a callback.

The Execution Context

The Context class (found in typer.models) is a subclass of click.Context. It acts as a container for the state of the current command execution. By type-hinting a parameter as typer.Context in a command or callback, Typer automatically injects the current context object.

This is particularly useful in global callbacks or parent commands to inspect the execution flow. For example, you can determine which subcommand is about to be executed using ctx.invoked_subcommand:

import typer

app = typer.Typer()

@app.callback()
def main(ctx: typer.Context):
if ctx.invoked_subcommand:
print(f"About to execute command: {ctx.invoked_subcommand}")

@app.command()
def create():
print("Creating item")

@app.command()
def delete():
print("Deleting item")

if __name__ == "__main__":
app()

The context also provides access to unparsed arguments via ctx.args, which is useful when a command is configured to allow extra arguments using context_settings={"allow_extra_args": True}.

Parameter Metadata in Callbacks

When implementing custom validation logic in a parameter callback, you often need metadata about the parameter itself—such as its name or how it was defined. Typer provides the CallbackParam class (a subclass of click.Parameter) for this purpose.

By declaring a parameter with the typer.CallbackParam type hint in your callback function, you gain access to the underlying Click parameter object.

import typer

def name_callback(ctx: typer.Context, param: typer.CallbackParam, value: str):
if ctx.resilient_parsing:
return
print(f"Validating param: {param.name}")
if value != "Camila":
raise typer.BadParameter("Only Camila is allowed")
return value

app = typer.Typer()

@app.command()
def main(name: str = typer.Option(..., callback=name_callback)):
print(f"Hello {name}")

In this example, param.name allows the callback to be generic; it knows it is validating the name option without having the name hardcoded into the logic.

Context-Aware Error Handling

Effective error handling in a CLI requires providing feedback that is relevant to the user's input. Typer leverages typer.BadParameter (an alias for click.BadParameter) to raise errors that are automatically associated with the specific parameter causing the issue.

Resilient Parsing and Shell Completion

A critical aspect of context-aware logic is respecting ctx.resilient_parsing. When a shell (like Bash or Zsh) requests completion options, Typer executes the callbacks to determine the current state. If your callback performs side effects (like printing to stdout) or raises errors during this phase, it can break the shell completion mechanism.

As seen in typer/models.py, Context inherits from click.Context, which includes the resilient_parsing flag. Developers should check this flag before performing actions that shouldn't occur during completion:

def custom_callback(ctx: typer.Context, value: str):
if ctx.resilient_parsing:
# We are in completion mode, don't perform validation or side effects
return value
# Normal execution logic here...

Internal Parameter Mapping with ParamMeta

While Context and CallbackParam are intended for end-user interaction, ParamMeta is an internal utility class used by Typer to bridge the gap between Python function signatures and Click's parameter system.

Defined in typer/models.py, ParamMeta stores the name, default value, and type annotation of a function parameter:

class ParamMeta:
empty = inspect.Parameter.empty

def __init__(
self,
*,
name: str,
default: Any = inspect.Parameter.empty,
annotation: Any = inspect.Parameter.empty,
) -> None:
self.name = name
self.default = default
self.annotation = annotation

Typer's internal utility get_params_from_function (in typer/utils.py) iterates through a command function's parameters, processes Annotated types and Option/Argument defaults, and packages them into ParamMeta objects. This metadata is then used to construct the final click.Command or click.Group. This design ensures that the rich type information provided by Python's type hinting system is preserved and correctly translated into CLI behavior.