Skip to content

Decompose errors.Join errors in SetException #977

Open
@lukasschwab

Description

@lukasschwab

Problem Statement

I have rich errors with Sentry-compatible stack traces. I use the Go standard library to Join them:

first := NewError(...)
second := NewError(...)

joined := errors.Join(first, second)

This is a common pattern for error aggregation: it was introduced into the standard library in Go 1.20 (Feb. 2023), and GitHub indexes 53.2k public instances.

I'd like to capture joined with the Sentry SDK and retain both errors — with their individual stack traces — on the resulting Sentry event.

Today, CaptureException yields an event with a single Exception (representing joined), with no stack trace information associated with it.

Solution Brainstorm: (Draft PR)

This SDK plays nice with errors.Wrap (see #792) and (github.com/pkg/errors).Wrap. It can introduce analogous support for errors.Join.

Compose Decompose
errors.Wrap errors.Unwrap
(github.com/pkg/errors).Wrap interface{ Cause() error } (source)
errors.Join interface{ Unwrap() []error } (docs)

Implementation

Two relevant excerpts from the standard library errors docs:

A non-nil error returned by Join implements the Unwrap() []error method.

It is invalid for an Unwrap method to return an []error containing a nil error value.

This represents a major change in the data model for error composition: wrapped errors form a clear causal chain, whereas joined errors are a tree that can contain chains of wrapped errors. Rather than looping linearly over the causal chain, SetException has to

  1. traverse a tree of decomposed errors
  2. handle more complex parent/child relationships — a "child" (composed error) can have several parents (first and second in the example above)

The draft diff linked above implements depth-first traversal of the error tree in a new errorTree type. It passes the SetException unit tests, plus additional cases including joined errors.

Open questions

  • Does Sentry's treatment of exceptions support multi-parental relationships/trees of exceptions?
    • Accordingly, how should joined errors be represented as []sentry.Exceptions?
  • How should maxExceptionDepth translate to a tree data model?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions