---
title: Format an exception chain for display
summary: Format an exception and its inner-exception chain for display.
status: draft
owner: saif-docgen
last_reviewed: 2026-09-15
library: SAIF.Framework.Common
reference_type: package
operation_id: OP-021
trigger: Caller logs or displays a caught exception
---

# Format an exception chain for display

Format an exception and its inner-exception chain for display, triggered when caller logs or displays a caught exception.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-021 |
| **Trigger** | Caller logs or displays a caught exception |
| **Inputs** | `instance`, `innerToOuter` |
| **Outputs** | Multi-section `string` |
| **Primary components** | ``ExceptionExtensions.GetFullFormattedException(this Exception, bool innerToOuter = true)`` |
| **Entry point** | `Common/SAIF.Common/Extensions/ExceptionExtensions.cs` |

## Steps

1. If the exception is null, return `string.Empty` (no throw). ([BR-049](../business-rules.md#br-049-formatting-a-null-exception-yields-an-empty-string-rather-than-throwing))
2. Walk the `InnerException` chain via the private `GetAllExceptions`, collecting outermost-first into a list.
3. If `innerToOuter` is true (the default), reverse the list so the innermost root-cause exception is reported first. ([BR-050](<../business-rules.md#br-050-exception-chains-are-reported-innermost-(root-cause)-first-by-default>))
4. Build a 50-character dashed rule using `StringExtensions.Repeat` and emit the header "Exception Summary (innermost exception first)".
5. For each exception emit "Exception #n of m - {TypeName}", the message, and "Source: {Source}" when `Source` is non-empty. ([BR-051](<../business-rules.md#br-051-the-formatted-exception-report-renders-a-summary-block-(type%2C-message%2C-source)-for-every-exception>))
6. In a second pass, emit each exception's stack trace under a "Stack Trace for exception #n" heading bracketed by dashed rules, skipping empty stack traces. ([BR-051](<../business-rules.md#br-051-the-formatted-exception-report-renders-a-summary-block-(type%2C-message%2C-source)-for-every-exception>))
7. Return the assembled string.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start(["Caller formats an<br>exception for display"]) --> C1{"Exception is null?"}
	C1 -->|Yes| Empty([Return string.Empty])
	C1 -->|No| S2["Walk InnerException chain:<br>collect outermost-first"]
	S2 --> C2{"innerToOuter is true<br>-default-?"}
	C2 -->|Yes| S3["Reverse list so innermost<br>is reported first"]
	C2 -->|No| S4["Keep outermost-first order"]
	S3 --> S5["Build dashed rule and<br>summary header"]
	S4 --> S5
	S5 --> S6["Emit summary block per<br>exception: type, message, source"]
	S6 --> S7["Emit stack trace per<br>exception, skipping empty ones"]
	S7 --> End([Return assembled string])
```

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `Common/SAIF.Common/Extensions/ExceptionExtensions.cs`
