Skip to content

← Error Handling with Exceptions, Retries and Warnings step 6 of 20

Easy Primitives

Wrap a Low-Level Error with raise from

Your app keeps its settings in a dictionary. When a setting is missing, settings["timeout"] raises KeyError: 'timeout'. That message does not say the config is at fault. Code that calls you should not need to know that you used a dictionary. Raise your own ConfigError instead, and keep the KeyError attached so the traceback still shows what went wrong underneath.

try:
    value = settings[name]
except KeyError as exc:
    raise ConfigError(f"missing setting: {name}") from exc

raise ... from exc stores the KeyError in the new error's __cause__ attribute. The traceback prints both errors, joined by this sentence:

The above exception was the direct cause of the following exception:

Leave out from exc and Python still keeps the KeyError in the new error's __context__ attribute. But __cause__ stays None, and the traceback joins the two errors with "During handling of the above exception, another exception occurred". That wording reads as if your except block itself crashed.

What to write

Fill in get_setting(settings, name):

  • Read the value with settings[name], and return it unchanged. An empty string is still a value.
  • If the name is missing, catch the KeyError and raise ConfigError(f"missing setting: {name}") from it.

Catch the KeyError instead of checking name in settings first. The tests check that __cause__ holds the KeyError.

What the driver reports

Keep ConfigError, chain_sentence and solve as they are. solve(settings=..., names=...) looks up each name in turn and returns lookups, one record per name:

  • name: the name it looked up.
  • value: the value get_setting returned, or None if it raised.
  • error: the class name and message of the error it raised, such as "ConfigError: missing setting: timeout", or None.
  • cause: the repr of the error's __cause__, such as "KeyError('timeout')", or None.
  • traceback_says: which sentence the traceback uses to join the error to an earlier one. It is "direct cause", "during handling", or "no earlier error". A lookup that succeeds reports "no error".