Skip to content

feat(pkg): Add package errors for the CLI#636

Open
vg006 wants to merge 10 commits into
goharbor:mainfrom
vg006:fix/logging
Open

feat(pkg): Add package errors for the CLI#636
vg006 wants to merge 10 commits into
goharbor:mainfrom
vg006:fix/logging

Conversation

@vg006
Copy link
Copy Markdown
Contributor

@vg006 vg006 commented Jan 23, 2026

Overview

Fixes #635.

This PR aims to provide the solution, as proposed & discussed in the issue. So as an initiative, the errors package is defined.

The layout of the error message is as follows.

<root error message>  
Code: <conditional> 
Cause: <conditional> 
Hints:
├── Hint 1
└── Hint 2 ...
Messages: <conditional> 
├── Message 1
│   └── Hint 1
└── Message 2
    ├── Hint 2.1
    └── Hint 2.2

Here <conditional> means - will only be rendered if present.

Preview

demo

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 80.51948% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 9.58%. Comparing base (60ad0bd) to head (4e15ac9).
⚠️ Report is 156 commits behind head on main.

Files with missing lines Patch % Lines
pkg/errors/utils.go 43.24% 15 Missing and 6 partials ⚠️
pkg/errors/errors.go 92.30% 6 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff            @@
##             main    #636      +/-   ##
=========================================
- Coverage   10.99%   9.58%   -1.41%     
=========================================
  Files         173     282     +109     
  Lines        8671   14119    +5448     
=========================================
+ Hits          953    1354     +401     
- Misses       7612   12639    +5027     
- Partials      106     126      +20     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vg006 vg006 marked this pull request as draft January 23, 2026 13:16
@vg006 vg006 marked this pull request as ready for review February 19, 2026 09:27
@NucleoFusion
Copy link
Copy Markdown
Contributor

func (e *Error) Error() string {
	if len(e.frames) == 0 {
		return ""
	}
	return e.frames[len(e.frames)-1].Message
}

Are we not supposed to play around this?
We currently rely on the RunE from cobra. And from what I recall, while logging the error, or any struct that is an instance of the error interface. uses the Error() for logging.

type error interface {
	Error() string
}

Cobra calls the err.Error() and in your implementation of Error() we show only the message in the last frame.
Instead I had in mind a format similar to

Cause: <e.Cause>

\\ Frame 1
Message: <e.msg 1>
    - Hint 1
    - Hint 2

\\ Frame 2
Message: <e.msg 2>
    - Hint 1
    - Hint 2


My attempt at invoking an error

y := errors.Newf("%s", "testing errors").WithHint("Try rm -rf").WithCause(errors.New("suicide"))
return errors.Wrap(y, "checking wrap")

This returns an error (when using RunE. As,

Error: testing errors

I believe it should include the Cause, All frames, and hints / messages

@vg006
Copy link
Copy Markdown
Contributor Author

vg006 commented Feb 23, 2026

@NucleoFusion
Yeah you are right, we are displaying the error as tree using the lipgloss style. Something like this,

Cause: <e.Cause>
|-- Message: <e.msg 1>
|   |-- Hint 1
|   `-- Hint 2
`-- Message: <e.msg 2>
    |-- Hint 1
    `-- Hint 2

For more info, here are the package doc and an example of what I mean.

func (e *Error) Error() string {
  if len(e.frames) == 0 {
  	return ""
  }
  return e.frames[len(e.frames)-1].Message
}

Are we not supposed to play around this?

Of course we can modify the Error() method.

  • I primarily designed in this way because I thought that we will be implementing and using a custom handler to register the logs (I have been looking into this for a while to implement such).
  • So we have the control of what info should be logged and how to be rendered. That's why, the Error() meant to return the message of the frame at the top and we have plenty of other utility functions to access each info of an error.

But now, if we aren't going with custom log handlers and delegate the error handling to Cobra, then the Error() method will be updated accordingly, to return the full error tree.

Hope this clarifies your doubts regarding the current implementation.

I will do the needful changes and update the PR, so that I will start the refactoring of commands in favor of #635 and #717, once these get into the upstream.

@NucleoFusion
Copy link
Copy Markdown
Contributor

I dont think we will be switching to a custom handler or using slog.Fatal or something similar.
At most, we will keep using RunE and silence errors such that we can log it how we see fit.
Still, I beleive that the Error() func should return the full string for now.
With all the options.

Of course, you can add formats such that when cause or frames or hints are nil, they get ignored and stuff.
But most of the times, if we do begin to attach Cause and Hints then we will probably show them anyway.

@NucleoFusion
Copy link
Copy Markdown
Contributor

Also, just for clarification
I believe that having the Wrap / Wrapf be chainable would be better than using it seperate
Then we dont need to assign a var / append it.
What do you think?
And possibly making Wrap take multiple errors, so when we have an array of errors we can handle that as well?

@vg006
Copy link
Copy Markdown
Contributor Author

vg006 commented Feb 23, 2026

The Wrap and Wrapf functions are inspired from the std/errors package and Harbor's errors package implementations.

I just added those for conventions and WithCause is meant for that purpose. I mean creating a new error, by wrapping it with a root Cause.

So yeah, we can remove them and update the methods accordingly.

@bupd
Copy link
Copy Markdown
Member

bupd commented Apr 21, 2026

@cubic-dev-ai review

Copy link
Copy Markdown
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

Introduces a dedicated pkg/errors package to standardize CLI error construction and rendering (including codes, causes, hints, and chained messages), addressing inconsistent/poor error reporting discussed in #635.

Changes:

  • Added pkg/errors with a framed error type, wrapping helpers, and formatted output using lipgloss/tree.
  • Added unit tests covering construction, wrapping, hints, frames, and helpers (Cause, Hints, Status).
  • Added new lipgloss styles in pkg/views to support consistent error formatting.

Reviewed changes

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

File Description
pkg/views/styles.go Adds new error-specific lipgloss styles used by the new error renderer.
pkg/errors/utils.go Adds Harbor error message/code extraction helpers used for Cause and Code rendering.
pkg/errors/errors.go Adds the core Error type (frames, cause, rendering, wrappers, helper functions).
pkg/errors/errors_test.go Adds comprehensive tests for the new pkg/errors behavior and formatting expectations.

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

Comment thread pkg/views/styles.go Outdated
Comment thread pkg/errors/utils.go
Comment thread pkg/errors/utils.go
Comment thread pkg/errors/errors.go
Comment thread pkg/errors/errors.go Outdated
@bupd
Copy link
Copy Markdown
Member

bupd commented Apr 23, 2026

@vg006 resolve copilot reviews and also rebase the pr.

Thanks

@vg006
Copy link
Copy Markdown
Contributor Author

vg006 commented Apr 23, 2026

Sure, I’m currently out of town. I’ll review the changes and update the branch shortly.

@vg006
Copy link
Copy Markdown
Contributor Author

vg006 commented Apr 27, 2026

@bupd
I have updated the branch with the changes as requested in the review. PTAL. Thank you.

vg006 added 10 commits May 7, 2026 18:50
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
Signed-off-by: vg006 <devvg006@gmail.com>
@vg006
Copy link
Copy Markdown
Contributor Author

vg006 commented May 7, 2026

@bupd

I request you to halt the merge for a while, currently making some iterations over it and will complete them soon. Will be there to explain them in the upcoming community meeting. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Fix improper logging and error handling

4 participants