---
title: Faults and error pipeline
summary: Fault contracts, error handlers, service behaviors, and what a caller receives when an operation fails.
status: draft
owner: Claims Systems Team
last_reviewed: 2026-09-10
---

# Faults and error pipeline

A failure in `ClaimIntake` reaches the caller in one of three ways. A validation failure in `SubmitClaim` is thrown as `FaultException<ClaimValidationFault>` and arrives as a typed SOAP fault. Any other exception thrown by `SubmitClaim` arrives as WCF's default generic fault, with no exception detail because `includeExceptionDetailInFaults` is false. A failure in `GetClaimStatus` never reaches the caller as a fault: the method catches it and returns null. In every case a `[LogErrorBehavior]` error handler logs the exception first and leaves the fault itself untouched.

## Fault surface summary

| Aspect | Finding |
| --- | --- |
| Declared fault contracts | 1 - `ClaimValidationFault` on `SubmitClaim` |
| Service behavior attributes | `[LogErrorBehavior]` on 1 service class |
| `IErrorHandler` implementations | `ClaimIntakeErrorHandler` (`src/SAIF.Claims.Intake.Service/Behaviors/ClaimIntakeErrorHandler.cs`) |
| `includeExceptionDetailInFaults` | false |
| Effect on callers | A caller sees a typed `ClaimValidationFault` for a failed validation, a generic fault with no detail for any other exception, and a null result when `GetClaimStatus` fails |

## Service behaviors

| Behavior | Applied to | Declared in | Effect |
| --- | --- | --- | --- |
| `[LogErrorBehavior]` | `ClaimIntake` | `src/SAIF.Claims.Intake.Service/Behaviors/LogErrorBehaviorAttribute.cs` | Installs `ClaimIntakeErrorHandler` on every channel dispatcher through `ApplyDispatchBehavior` |
| `<serviceDebug includeExceptionDetailInFaults="false"/>` | `ClaimIntake` (`behaviorConfiguration="ClaimIntakeBehavior"`) | `Web.config` `<serviceBehaviors>` | Exception type, message, and stack trace are not included in generic faults |
| `<serviceMetadata httpGetEnabled="true"/>` | `ClaimIntake` (`behaviorConfiguration="ClaimIntakeBehavior"`) | `Web.config` `<serviceBehaviors>` | The WSDL is published at `ClaimIntake.svc?wsdl` |

The code attribute and the configuration behavior do not interact: the attribute adds an error handler, and `serviceDebug` only controls whether WCF puts exception detail into a generic fault.

## Error handler

| Field | Value |
| --- | --- |
| **Type** | `ClaimIntakeErrorHandler` : `IErrorHandler` |
| **Source** | `src/SAIF.Claims.Intake.Service/Behaviors/ClaimIntakeErrorHandler.cs` |
| **Installed by** | `LogErrorBehaviorAttribute` : `IServiceBehavior` - `ApplyDispatchBehavior` |
| **Scope** | Every channel dispatcher on every service carrying the attribute |
| **`HandleError` return** | `false` - the exception is not considered handled |
| **`ProvideFault` behavior** | Leaves the fault unchanged - a thrown `FaultException<ClaimValidationFault>` is sent as the typed fault and every other exception produces the default fault |

`HandleError` writes one error entry through the log surface that records the exception type, message, stack trace, the SOAP action of the failing call, and the Windows identity of the caller, then returns `false`. Returning `false` means the exception continues through the WCF pipeline, so the fault the caller receives is whatever WCF would have produced without the handler.

### Logged exception detail

| Field | Value written | Source of the value |
| --- | --- | --- |
| Exception type | Full type name | `error.GetType().FullName` |
| Message | Exception message | `error.Message` |
| Stack trace | Full stack trace | `error.StackTrace` |
| SOAP action | Action of the failing request | `OperationContext.Current.IncomingMessageHeaders.Action` |
| Caller identity | Windows account name | `ServiceSecurityContext.Current.WindowsIdentity.Name` |

| Aspect | Finding |
| --- | --- |
| Log surface | `ILogService` |
| Destination | Not determined from source |
| Failure of the logger itself | The logging call is wrapped in a try/catch that discards the exception, so a logging failure is silent and the fault path is unaffected |

## Error pipeline diagram

The following diagram visualizes how an exception becomes a fault.

```mermaid
flowchart TD
    OP["Operation throws<br>an exception"] --> DISP["Channel dispatcher"]
    DISP --> PROVIDE["ClaimIntakeErrorHandler.ProvideFault<br>leaves the fault unchanged"]
    PROVIDE --> KIND{"Exception type"}
    KIND -->|"FaultException of ClaimValidationFault"| TYPED["Typed fault ClaimValidationFault"]
    KIND -->|"Any other exception"| DEFAULT["WCF produces the default fault<br>with no exception detail"]
    TYPED --> CALLER["Caller receives SOAP fault"]
    DEFAULT --> CALLER
    DISP --> HANDLER["ClaimIntakeErrorHandler.HandleError"]
    HANDLER --> LOG["Exception detail logged<br>via ILogService"]
    HANDLER --> RET{"HandleError returns"}
    RET -->|"false"| NOTHANDLED["Exception not considered handled<br>WCF pipeline continues"]
```

## Declared fault contracts

| Fault type | Declared on | Members | Raised when |
| --- | --- | --- | --- |
| `ClaimValidationFault` | [`SubmitClaim`](contracts/claim-intake.md#submitclaim) | `Code`, `FieldErrors`, `Message` | The injury date is in the future (BR-CLM-001) or the employer policy is not active on the injury date (BR-CLM-002) |

## Failure modes by operation

| Operation | Failure | What the caller receives | Detail exposed |
| --- | --- | --- | --- |
| [`SubmitClaim`](contracts/claim-intake.md#submitclaim) | Injury date in the future or policy not active on the injury date | Typed fault `ClaimValidationFault` | `Code`, `Message`, and the list of failing fields |
| [`SubmitClaim`](contracts/claim-intake.md#submitclaim) | `PKG_CLAIM_INTAKE.INSERT_CLAIM` fails with `OracleException` | Generic SOAP fault | None |
| [`GetClaimStatus`](contracts/claim-intake.md#getclaimstatus) | No claim matches the claim number | Default value with no fault | None |
| [`GetClaimStatus`](contracts/claim-intake.md#getclaimstatus) | Any exception during the lookup | Default value with no fault | None |
| [`FlagClaimForReview`](contracts/claim-intake.md#flagclaimforreview) | `PKG_CLAIM_INTAKE.ADD_REVIEW_FLAG` fails with `OracleException` | Nothing - a one-way operation returns no message and the failure is only logged | None |

## Swallowed failures

| Location | Behavior | Consequence |
| --- | --- | --- |
| `ClaimIntake.GetClaimStatus` (`src/SAIF.Claims.Intake.Service/ClaimIntake.svc.cs:104`) | A `catch (Exception)` block logs the exception through `ILogService` and returns null without rethrowing | The caller cannot distinguish a database failure from an unknown claim number, and `ClaimIntakeErrorHandler` never sees the exception |

## Related documentation
- [Index](index.md)
- Overview
- Architecture
- Activation and hosting
- Operations
- Authentication and authorization
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Data model
- Operational runbook
- Tech debt

## Sources
- `src/SAIF.Claims.Intake.Service/Behaviors/LogErrorBehaviorAttribute.cs`
- `src/SAIF.Claims.Intake.Service/Behaviors/ClaimIntakeErrorHandler.cs`
- `src/SAIF.Claims.Intake.Service/ClaimIntake.svc.cs`
- `src/SAIF.Claims.Intake.Service/DataContracts/ClaimValidationFault.cs`
- `src/SAIF.Claims.Intake.Service/Web.config`
