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
Proposal Details
Hello,
I have a custom error type defined as follows:
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:
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:
it would be great if fmt.Errorf() do lazy formatting out of box
Best Regards,
Vahid