unwrapErrorChain walks the error chain via errors.Unwrap and returns a slice of individual message contributions, from outermost to innermost. Each entry contains only the message added at that level (i.e. the inner error's message is stripped).
(err error)
| 333 | // individual message contributions, from outermost to innermost. Each entry contains |
| 334 | // only the message added at that level (i.e. the inner error's message is stripped). |
| 335 | func unwrapErrorChain(err error) []string { |
| 336 | var chain []string |
| 337 | current := err |
| 338 | for current != nil { |
| 339 | next := errors.Unwrap(current) |
| 340 | if next == nil { |
| 341 | chain = append(chain, current.Error()) |
| 342 | break |
| 343 | } |
| 344 | outerMsg := current.Error() |
| 345 | innerMsg := next.Error() |
| 346 | // Strip the inner error's message from the current error's message |
| 347 | // to isolate this level's own contribution. This assumes the standard |
| 348 | // fmt.Errorf("prefix: %w", inner) pattern (colon-space separator). |
| 349 | // If the pattern does not match, the full message is used as a fallback |
| 350 | // so no information is lost. |
| 351 | suffix := ": " + innerMsg |
| 352 | if strings.HasSuffix(outerMsg, suffix) { |
| 353 | chain = append(chain, outerMsg[:len(outerMsg)-len(suffix)]) |
| 354 | } else { |
| 355 | // Format does not follow the standard ": %w" pattern; keep the full message. |
| 356 | chain = append(chain, outerMsg) |
| 357 | } |
| 358 | current = next |
| 359 | } |
| 360 | return chain |
| 361 | } |
| 362 | |
| 363 | // formatMultilineError formats a plain error message, indenting any newlines so that |
| 364 | // continuation lines are visually subordinate to the leading "✗" prefix. |
no test coverage detected