pkg/errors captures a stack trace of when the error occurred, and attaches it to the error. This information doesn't change as the error moves through the program.
errtrace captures a 'return trace'--every 'return' statement that the error passes through. This information is appended to at each return site.
This gives you a different view of the code path: the stack trace is the path that led to the error, while the return trace is the path that the error took to get to the user.
The difference is significant because in Go, errors are just plain values that you can store in a struct, pass between goroutines etc. When the error passes to another goroutine, the stack trace from the original goroutine can become less useful in debugging the root cause of the error.
As an example, the Try it out section (https://github.com/bracesdev/errtrace/#try-it-out) in the README includes an example of a semi-realistic program comparing the stack trace and the return trace for the same failure.
>This repository has been archived by the owner on Dec 1, 2021. It is now read-only.
It's largely complete so it is essentially fine at the moment, but it won't be adapted to future language or community changes. A future landmine.
tbh I'm not sure what the current popular option is for wrapping with stack traces.
Re join: it isn't a joiner-error, it has no need to do anything for that. Just stdlib-join-then-wrap.
"You can build X by hand too" has little to do with why people choose to create or use libraries.
In my experience, "you can build X by hand" is the Go community's preferred approach.