Skip to content

ToKnownError (ExceptionHandler)

ExceptionHandler.ToKnownError is the final step in translating an HTTP failure into a caller-meaningful domain exception, drawn from SAIF.Web.API.Core's SAIF.API.Exceptions.* hierarchy.

Field Value
Operation ID OP-09
Trigger EnsureSuccessfulResponse step 4; also directly callable by consumers (public static).
Inputs HttpStatusCode status, raw response content.
Outputs Always throws.
Primary components ExceptionHandler.ToKnownError(HttpStatusCode, string)
Entry point src/SAIF.Web.API.Clients/ExceptionHandler.cs

Steps

  1. If content is non-empty, JToken.Parse(content) and iterate its tokens (BR-CLI-008).
  2. On failure: catch { sb.Append(content); } — a parse failure makes the raw content the message.
  3. For each token whose Path (lower-cased) is one of errormessage, exceptionmessage, message, usermessage, append token.First.ToString() (BR-CLI-008).
  4. Matching is on the token path, so only top-level properties with those names are harvested. Multiple matches are concatenated as separate lines.
  5. If nothing was harvested (blank builder), fall back to the raw content (BR-CLI-008).
  6. Guarantees a non-empty message whenever content was non-empty.
  7. switch (status): 404 → NoMatchingDataException; 403 or 401 → SAIF.API.Exceptions.UnauthorizedAccessException; 400 → InvalidDataException; default (all other statuses, including 0) → InternalServerError. Set HttpStatusCode = status on the thrown instance (BR-CLI-007).
  8. The thrown exception types are constructed in SAIF.Web.API.Core (src/SAIF.Web.API.Core/SAIFException.cs): each constructor calls the base Exception(string) constructor with a default message, and the HttpStatusCode property is set by object initializer — no further logic.
  9. Always throws; never returns.

Process flow

The following diagrams visualize this operation's control flow, split by concern so each renders at a readable width.

The first diagram shows message harvesting/fallback and the 404/401 or 403 status outcomes:

flowchart TD
    Start([ToKnownError called]) --> Parse[Parse content as JToken]
    Parse --> Harvest["Harvest<br>errormessage/<br>exceptionmessage/<br>message/usermessage<br>tokens"]
    Harvest --> Fallback{Message harvested?}
    Fallback -->|No| RawContent[Fall back to raw content]
    Fallback -->|Yes| Switch
    RawContent --> Switch{status?}
    Switch -->|404| NoMatch(["Throw<br>NoMatchingDataException"])
    Switch -->|401 or 403| Unauth(["Throw<br>UnauthorizedAccess<br>Exception"])

The second diagram shows the remaining 400 and other status outcomes:

flowchart TD
    Switch{status?} -->|400| Invalid(["Throw<br>InvalidDataException"])
    Switch -->|other| Internal(["Throw<br>InternalServerError"])

Failure and edge-case behavior

  • A non-JSON or malformed content falls back to the raw content as the exception message (step 1).
  • Status codes other than 400/401/403/404 — including 0 (transport failure) — map to InternalServerError.

Sources

  • src/SAIF.Web.API.Clients/ExceptionHandler.cs
  • src/SAIF.Web.API.Core/SAIFException.cs