Skip to content

fix: format wrapped error chains with newlines and indentation#21384

Merged
pelikhan merged 1 commit intomainfrom
copilot/format-multi-errors-output
Mar 17, 2026
Merged

fix: format wrapped error chains with newlines and indentation#21384
pelikhan merged 1 commit intomainfrom
copilot/format-multi-errors-output

Conversation

Copy link
Contributor

Copilot AI commented Mar 17, 2026

Long fmt.Errorf-wrapped error chains are rendered as a single hard-to-read line. Each layer of context is colon-concatenated, making it difficult to identify the root cause at a glance.

Changes

  • pkg/console/console.go — adds FormatErrorChain(err error) string that walks errors.Unwrap to extract per-level messages and formats them with consistent 2-space indentation. Also handles errors.Join-style multi-errors whose .Error() output contains newlines.
  • cmd/gh-aw/main.go — top-level error handler now calls FormatErrorChain(err) instead of FormatErrorMessage(errMsg) for unformatted errors.
  • pkg/cli/add_command.go — compile-step error display uses FormatErrorChain.

Before / After

Before:

✗ workflow 'githubnext/agentics/workflows/q.md@main' not found: failed to download workflow from githubnext/agentics/workflows/q.md@main: failed to fetch file content from githubnext/agentics/workflows/q.md@main: HTTP 404: Not Found (https://...)

After:

✗ workflow 'githubnext/agentics/workflows/q.md@main' not found
  failed to download workflow from githubnext/agentics/workflows/q.md@main
  failed to fetch file content from githubnext/agentics/workflows/q.md@main
  HTTP 404: Not Found (https://...)

The suffix-stripping logic assumes the standard fmt.Errorf("prefix: %w", inner) pattern; if the pattern doesn't match the full message is used as a fallback so no information is lost.

…dability

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan pelikhan marked this pull request as ready for review March 17, 2026 12:11
Copilot AI review requested due to automatic review settings March 17, 2026 12:11
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves readability of long fmt.Errorf("%w")-wrapped error chains by rendering each unwrap layer on its own indented line (and indenting joined/multiline errors), then updates CLI call sites to use the new formatting.

Changes:

  • Add console.FormatErrorChain(err) plus helpers to unwrap and pretty-print error chains with indentation.
  • Switch top-level CLI error printing (and workflow compile error output) to use FormatErrorChain.
  • Add unit tests for basic wrapped and joined error formatting behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
pkg/console/console.go Adds FormatErrorChain and helpers for unwrapping/formatting multiline error chains.
pkg/console/console_formatting_test.go Adds tests validating basic chain formatting, multiline output, and indentation behavior.
pkg/cli/add_command.go Uses FormatErrorChain when printing compile errors.
cmd/gh-aw/main.go Uses FormatErrorChain(err) for unformatted top-level errors.
Comments suppressed due to low confidence (1)

pkg/console/console.go:324

  • formatMultilineError currently drops empty continuation lines (if line != ""), which changes the original error text for messages that intentionally include blank lines (e.g. \n\n separators in user instructions). To avoid losing formatting, preserve empty lines by still writing the newline + indentation even when line is empty.
	for _, line := range lines[1:] {
		if line != "" {
			sb.WriteString("\n  ")
			sb.WriteString(line)
		}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +263 to +274
var sb strings.Builder
sb.WriteString(applyStyle(styles.Error, "✗ "))
sb.WriteString(chain[0])
for _, msg := range chain[1:] {
// Each message in the chain may itself contain newlines (e.g. from errors.Join
// nested inside a wrapping error); expand them all with consistent indentation.
for line := range strings.SplitSeq(msg, "\n") {
if line != "" {
sb.WriteString("\n ")
sb.WriteString(line)
}
}
Comment on lines +296 to +304
// If the pattern does not match, the full message is used as a fallback
// so no information is lost.
suffix := ": " + innerMsg
if strings.HasSuffix(outerMsg, suffix) {
chain = append(chain, outerMsg[:len(outerMsg)-len(suffix)])
} else {
// Format does not follow the standard ": %w" pattern; keep the full message.
chain = append(chain, outerMsg)
}
err: errors.Join(errors.New("error one"), errors.New("error two")),
expectedContains: []string{"✗", "error one", "error two"},
expectMultiLine: true,
},
@pelikhan pelikhan merged commit f9ee68b into main Mar 17, 2026
93 checks passed
@pelikhan pelikhan deleted the copilot/format-multi-errors-output branch March 17, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants