Skip to content

proposal: errors: unwarap joinError to avoid deeply-nested joins #65676

Closed as not planned
@sethvargo

Description

@sethvargo

Proposal Details

The current implementation of joinError appends the given errors onto an internal []error. However, it does not take into account itself, leading to unexpected internal structures. This is perhaps best illustrated by an example:

var merrA error
merrA = errors.Join(merrA, fmt.Errorf("one"))
merrA = errors.Join(merrA, fmt.Errorf("two"))
merrA = errors.Join(merrA, fmt.Errorf("three"))

var merrB error
merrB = errors.Join(merrB, fmt.Errorf("one"), fmt.Errorf("two"), fmt.Errorf("three"))

One would likely expect merrA and merrB to be structurally equal. While they "print out" the same error, their internal representation differs:

merrA = &joinError{
  errs: []error{
    fmt.Errorf("one"),
    &joinError{
      errs: []error{
        fmt.Errorf("two"),
        &joinError{
          errs: []error{
            fmt.Errorf("three"),
          },
        },
      },
    },
  },
}

merrB = &joinError{
  errs: []error{
    fmt.Errorf("one"),
    fmt.Errorf("two"),
    fmt.Errorf("three"),
  }
}

My proposal is that errors.Join special-case the internal joinError type to "unwrap" the inner errors and flatten the slice.

I believe this change is fully backwards-compatible with any documented APIs and public interfaces. There are no test cases that cover this expected nesting as shown in #65360.

I also believe this will lead to more performant error printing, since it reduces the need to recurse multierrors, but I do not have time to gather data and benchmark my gut feeling.

I could not find any corresponding issues, but "errors" and "unwrap" are not particularly unique keywords, so apologies if I missed them.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions