fmt.Println() not prints wrapped custom errors


i have a CustomError type and implemented the error interface and the Unwrap()method in the typical manner. Now lets say i have some 3 levels deep function call stack. All levels add some errors.

Level1 (deepest) wrap some io error by doing:
fmt.Errorf(„err occured in level1 %w“, ioErr)

Level2 wrap above returned level1 err into my custom error:
return NewCustomError(„err occurred in level2, lvl1Err)

Level3 wrap my above returned custom error again into a „normal“ go error, by doing:
fmt.Errorf(„err occured in level3 %w“, customErr)

In main() i do now some fmt.Println(err) of level3 error. But the printed chain just shows the level3 error and level2 error. As soon as Println() „hits“ my custom error it stops „chaining of print“.

The following i did:

  1. If i replace my custom error in level2 with also a fmt.Errorf() call, the main‘s fmt.Println() prints all errors of all levels.

  2. If i stop debugger in main(), i can clearly see, even with using custom error, that all errors are existing in the chain.

  3. if i use errors.Unwrap() of golang, i can manually unwrap and print all errors, including my custom error.

In short: Every error is chained correctly, but for whatever reason fmt.Println(err) stops wrapped printing, when reaching the custom error.

I always thought fmt.Println() does the same thing, i did in point3 above: Hangling through all errors, by calling Unwrap() and printing the error until it is nil. Instead it stops when reaching a custom error. And i want to know why?

You can find simple sample code, for better understanding, here:

Any help is very appreciated,
best wishes

Could it be caused by this line setting your actual error as nil?

Perhaps, this can be more insightful link;


thx for the answer! The line you mentioned is not the problem. But in your example code, in line15, the return e.Msg + e.Err.Error() code is the key point. Btw: It should be return e.Msg + „: „ + e.Err.Error() to follow the same pattern, the Go standard library use.

I opened a StackOverflow question, which illustrates my point way better, than my above post here does, and it also includes a way more simple and shorter example, than i did here (sorry for that):

I am still a golang newbie, so i apologize, if i was confusing. But thx for the reply, playground code line15 indeed nailed it.