Problem
Hydra’s default exception rendering currently offers two extremes:
CompactHydraException subclasses are reduced to their message.
HYDRA_FULL_ERROR=1 exposes the complete Python traceback, including Hydra and OmegaConf implementation frames.
run_and_report() currently handles compact exceptions with:
if isinstance(ex, CompactHydraException):
sys.stderr.write(str(ex) + os.linesep)
if isinstance(ex.__cause__, OmegaConfBaseException):
sys.stderr.write(str(ex.__cause__) + os.linesep)
This loses useful information:
- The user-code location that triggered the error.
- Explicit chained causes other than
OmegaConfBaseException.
- The distinction between the high-level Hydra error and its underlying cause.
This is especially problematic for callable APIs such as hydra.utils.instantiate(). An application may receive:
Error locating target my_app.Model
full_key: model._target_
without seeing either the line of application code that called instantiate() or the chained ImportError.
The current behavior conflates two separate goals:
- Hide irrelevant Hydra and OmegaConf implementation frames.
- Hide all traceback frames.
Hydra should do the first without doing the second.
Goal
Modernize Hydra’s default exception rendering so that ordinary users receive a concise but useful traceback containing:
- Relevant application frames.
- The high-level Hydra exception and configuration context.
- Explicit chained causes in a clear, controlled form.
- No routine Hydra or OmegaConf implementation frames.
For example:
Traceback (most recent call last):
File "/app/train.py", line 42, in build_model
model = instantiate(cfg.model)
InstantiationException: Error locating target my_app.Model
full_key: model._target_
Caused by: ImportError: No module named my_app
The exact formatting can be decided during implementation, but the information model should be consistent.
Direction
Replace the current message-only handling of CompactHydraException with a shared exception-rendering policy.
The default renderer should:
- Preserve user-code frames, including:
- The task-function frame.
- Calls to public Hydra APIs such as
instantiate().
- User target or constructor frames when those raise.
- Filter routine internal frames from
hydra.* and omegaconf.*.
- Render explicit
__cause__ chains without requiring each wrapper exception to copy the cause into its own message.
- Render each cause once.
- Preserve useful Hydra metadata such as
full_key.
- Avoid exposing complete internal tracebacks merely to explain a common application error.
- Fall back safely to standard Python traceback rendering if Hydra cannot apply its filtering policy.
HYDRA_FULL_ERROR=1 and debugger detection should continue to bypass filtering and expose the complete native Python traceback.
Acceptance criteria
- An
InstantiationException raised inside a Hydra task displays the application line that called instantiate().
- If target construction enters user code and that code raises, the relevant user target frames remain visible.
- Hydra and OmegaConf implementation frames are omitted from default output.
- An explicit chained
ImportError is displayed as a cause without being copied into the InstantiationException message.
- Chained causes appear exactly once.
- Compact configuration errors retain their existing actionable messages and configuration metadata.
HYDRA_FULL_ERROR=1 continues to produce the complete native traceback and chain.
- Running under a debugger continues to bypass sanitization.
- Focused tests cover:
- Compact exceptions with and without causes.
instantiate() call-site failures.
- Exceptions raised inside user targets.
- OmegaConf causes.
- Full-error and debugger behavior.
- Current user and development documentation explains the default filtered traceback and the full-error debugging facility.
Related work
Problem
Hydra’s default exception rendering currently offers two extremes:
CompactHydraExceptionsubclasses are reduced to their message.HYDRA_FULL_ERROR=1exposes the complete Python traceback, including Hydra and OmegaConf implementation frames.run_and_report()currently handles compact exceptions with:This loses useful information:
OmegaConfBaseException.This is especially problematic for callable APIs such as
hydra.utils.instantiate(). An application may receive:without seeing either the line of application code that called
instantiate()or the chainedImportError.The current behavior conflates two separate goals:
Hydra should do the first without doing the second.
Goal
Modernize Hydra’s default exception rendering so that ordinary users receive a concise but useful traceback containing:
For example:
The exact formatting can be decided during implementation, but the information model should be consistent.
Direction
Replace the current message-only handling of
CompactHydraExceptionwith a shared exception-rendering policy.The default renderer should:
instantiate().hydra.*andomegaconf.*.__cause__chains without requiring each wrapper exception to copy the cause into its own message.full_key.HYDRA_FULL_ERROR=1and debugger detection should continue to bypass filtering and expose the complete native Python traceback.Acceptance criteria
InstantiationExceptionraised inside a Hydra task displays the application line that calledinstantiate().ImportErroris displayed as a cause without being copied into theInstantiationExceptionmessage.HYDRA_FULL_ERROR=1continues to produce the complete native traceback and chain.instantiate()call-site failures.Related work
HYDRA_FULL_ERROR=1after routine errors: Stop advertising HYDRA_FULL_ERROR in user-facing errors #3329