-
Notifications
You must be signed in to change notification settings - Fork 18.6k
Open
Labels
LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposal
Milestone
Description
Proposal Details
Hello,
I have a custom error type defined as follows:
type ErrorInfo struct {
ErrCode int
Err error
}
func NewErrInfo(errCode int, err error) *ErrorInfo {
return &ErrorInfo{
ErrCode: errCode,
Err: err,
}
}
func (ei *ErrorInfo) Error() string {
if ei.Err == nil {
return fmt.Sprintf("error code (%d)", ei.ErrCode)
}
return fmt.Sprintf("%s (%d)", ei.Err.Error(), ei.ErrCode)
}This *ErrorInfo object is typically created in a low-level function with only the ErrCode set. The actual human-readable error corresponding to ErrCode is assigned later in a high-level function.
The workflow is:
- A low-level function creates a *ErrorInfo with just the error code.
- This object is wrapped in an error using %w and propagated up through intermediate functions, which may enrich the error.
- In the high-level function, I use errors.As() to locate the original *ErrorInfo inside the wrapped error chain.
- Once found, I modify the object (for example, mapping ErrCode to a human-readable error and setting ErrInfo.Err).
- I then want to print the top-level error message so it reflects the updated *ErrorInfo.
The problem with using fmt.Errorf() directly is that it constructs the error string immediately. If the *ErrorInfo is modified later, these changes are not reflected in the printed message.
Workaround: lazy error formatting
To solve this, I created a lazyError wrapper that defers formatting until Error() is called:
type lazyError struct {
format string
args []interface{}
}
func (le *lazyError) Error() string {
return fmt.Errorf(le.format, le.args...).Error()
}
func (le *lazyError) Unwrap() []error {
err := fmt.Errorf(le.format, le.args...)
switch x := err.(type) {
case interface{ Unwrap() error }:
return []error{x.Unwrap()}
case interface{ Unwrap() []error }:
return x.Unwrap()
default:
return nil
}
}
func Errorf(format string, args ...interface{}) error {
return &lazyError{
format: format,
args: args,
}
}it would be great if fmt.Errorf() do lazy formatting out of box
Best Regards,
Vahid
Metadata
Metadata
Assignees
Labels
LibraryProposalIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolIssues describing a requested change to the Go standard library or x/ libraries, but not to a toolProposal