C#
Exception Handling
Serialization
Programming
.NET

How to serialize an Exception object in C?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Serializing exceptions is useful for logging, diagnostics APIs, and cross-process error reporting. In modern .NET, the safest pattern is serializing a controlled error model instead of trying to serialize runtime exception objects directly. You can still support legacy exception serialization patterns, but they should be used intentionally and with security awareness.

What You Usually Need To Serialize

Most systems do not need a full raw Exception instance. They need stable fields such as:

  • exception type
  • message
  • stack trace
  • inner exception chain
  • selected context data

Building an explicit error payload avoids brittle serializer behavior and accidental leakage of sensitive fields.

Preferred Approach: Map Exception to DTO

Create a serializable model and map from Exception.

csharp
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Text.Json;
5
6public sealed class ExceptionDto
7{
8    public string Type { get; init; } = string.Empty;
9    public string Message { get; init; } = string.Empty;
10    public string? StackTrace { get; init; }
11    public ExceptionDto? Inner { get; init; }
12    public Dictionary<string, string> Data { get; init; } = new();
13
14    public static ExceptionDto FromException(Exception ex)
15    {
16        var data = new Dictionary<string, string>();
17        foreach (DictionaryEntry entry in ex.Data)
18        {
19            var key = entry.Key?.ToString() ?? "null";
20            var value = entry.Value?.ToString() ?? "null";
21            data[key] = value;
22        }
23
24        return new ExceptionDto
25        {
26            Type = ex.GetType().FullName ?? ex.GetType().Name,
27            Message = ex.Message,
28            StackTrace = ex.StackTrace,
29            Inner = ex.InnerException is null ? null : FromException(ex.InnerException),
30            Data = data
31        };
32    }
33}
34
35class Program
36{
37    static void Main()
38    {
39        try
40        {
41            throw new InvalidOperationException("Example failure");
42        }
43        catch (Exception ex)
44        {
45            var dto = ExceptionDto.FromException(ex);
46            var json = JsonSerializer.Serialize(dto, new JsonSerializerOptions { WriteIndented = true });
47            Console.WriteLine(json);
48        }
49    }
50}

This gives predictable payloads and good forward compatibility.

Why Not Serialize Raw Exception Blindly

Raw exception graphs can include non-serializable members, environment-specific details, and framework internals that change across versions. They may also include data you do not want exposed externally.

For API responses, prefer a constrained contract:

  • user-safe message
  • error code
  • correlation identifier
  • optional debug data in internal-only channels

Legacy Exception Serialization in Custom Exceptions

If you build custom exceptions and need compatibility with classic serialization mechanisms, implement serialization constructor and GetObjectData.

csharp
1using System;
2using System.Runtime.Serialization;
3
4[Serializable]
5public class DomainException : Exception
6{
7    public string ErrorCode { get; }
8
9    public DomainException(string message, string errorCode) : base(message)
10    {
11        ErrorCode = errorCode;
12    }
13
14    protected DomainException(SerializationInfo info, StreamingContext context) : base(info, context)
15    {
16        ErrorCode = info.GetString(nameof(ErrorCode)) ?? "UNKNOWN";
17    }
18
19    public override void GetObjectData(SerializationInfo info, StreamingContext context)
20    {
21        info.AddValue(nameof(ErrorCode), ErrorCode);
22        base.GetObjectData(info, context);
23    }
24}

Use this only when the transport truly requires that style.

Logging Pipeline Integration

Many teams serialize exceptions for structured logging.

csharp
1catch (Exception ex)
2{
3    var dto = ExceptionDto.FromException(ex);
4    var payload = JsonSerializer.Serialize(dto);
5    Console.WriteLine(payload); // replace with logger sink
6}

Keep logging and API contracts separate so internal stack traces do not leak to clients.

Handling Inner Exception Depth Safely

Deep inner-exception chains can generate large payloads. Add optional max depth control in your mapper if logs or events have strict size limits. Truncating safely with a marker field is better than dropping the whole error event.

Security and Compliance Notes

Before serializing exception data:

  • remove secrets from connection strings and tokens
  • avoid dumping raw request bodies in error payloads
  • apply redaction policy consistently

Exception serialization is observability, but it is also a data-handling surface.

Common Pitfalls

  • Trying to serialize raw exception objects directly into public API responses.
  • Using legacy binary serialization in new systems without strong justification.
  • Forgetting to include inner exception details when needed for debugging.
  • Logging sensitive data from exception context fields without redaction.
  • Coupling user-facing error schema to framework exception type names.

Summary

  • Prefer mapping exceptions into explicit DTO models for safe serialization.
  • Use System.Text.Json for predictable modern JSON payloads.
  • Support classic exception serialization only for legacy compatibility needs.
  • Separate internal diagnostic detail from external API error contracts.
  • Apply redaction and size-control policies to serialized exception data.

Course illustration
Course illustration

All Rights Reserved.