Repository navigation
V5 unable capture error #2869
Description
Activity
- changed the title
[-]V5 Response committed no effect[/-][+]V5 HTTPErrorHandler unable capture error[/+]on Jan 20, 2026 - changed the title
[-]V5 HTTPErrorHandler unable capture error[/-][+]V5 unable capture error[/+]on Jan 20, 2026 You probably solved it yourself but
resp, err := echo.UnwrapResponse(c.Response())shadows the function argumenterrvariable. Better way to do it would be to thisif resp, _ := echo.UnwrapResponse(c.Response()); resp != nil && resp.Committed { return }
Default error handler is implemented like that:
Lines 365 to 413 in 9500f27
func DefaultHTTPErrorHandler(exposeError bool) HTTPErrorHandler { return func(c *Context, err error) { if r, _ := UnwrapResponse(c.response); r != nil && r.Committed { return } code := http.StatusInternalServerError var sc HTTPStatusCoder if errors.As(err, &sc) { if tmp := sc.StatusCode(); tmp != 0 { code = tmp } } var result any switch m := sc.(type) { case json.Marshaler: // this type knows how to format itself to JSON result = m case *HTTPError: sText := m.Message if sText == "" { sText = http.StatusText(code) } msg := map[string]any{"message": sText} if exposeError { if wrappedErr := m.Unwrap(); wrappedErr != nil { msg["error"] = wrappedErr.Error() } } result = msg default: msg := map[string]any{"message": http.StatusText(code)} if exposeError { msg["error"] = err.Error() } result = msg } var cErr error if c.Request().Method == http.MethodHead { // Issue #608 cErr = c.NoContent(code) } else { cErr = c.JSON(code, result) } if cErr != nil { c.Logger().Error("echo default error handler failed to send error to client", "error", cErr) // truly rare case. ala client already disconnected } } } and
_ = c.JSON(http.StatusOK, nil)would output{}to the client. so this probably should be_ = c.JSON(http.StatusOK, map[string]string{"error": err.Error()})
Yes, this is a small issue that is easy to overlook.
In version V4, resp, err := echo.UnwrapResponse(c.Response()) is not needed, and err will not be overwritten.
I am upgrading from version V4 to version V5.I have note about it to the release notes.
@zuozhehao , what was the most complex part and what most timeconsuming when upgrading from
v4tov5?@aldas According to the upgrade documentation, the upgrade was completed quickly, and all features worked normally during gray (canary) testing.
In V4, Recover provides a dedicated handler with the type
type LogErrorFunc func(c echo.Context, err error, stack []byte) error,
allowing panic handling and stack retrieval to be done independently.In V5, this no longer exists; everything is handled through HTTPErrorHandler
func(c echo.Context, err error).Since the panic is wrapped using
fmt.Errorf("[PANIC RECOVER] %w %s", tmpErr, stack[:length]),
it is currently not convenient to determine whether an error is caused by a panic, nor to reliably extract the stack trace.@aldas Is there any good recommendation or solution for this.
Are you just logging that stack? I think we can bring that handler function back.
@aldas Yes, at the moment it is not possible to accurately identify the error type within HTTPErrorHandler.
If we change tmpErr to a custom error type, such as PanicError, would that be an appropriate approach.
Lines 78 to 80 in 9500f27
stack := make([]byte, config.StackSize) length := runtime.Stack(stack, !config.DisableStackAll) tmpErr = fmt.Errorf("[PANIC RECOVER] %w %s", tmpErr, stack[:length]) Reacted by Martti T.@zuozhehao I have merged #2871. I'll tag new patch release in couple of days but you can use it if you add direct commit as dependency.
go get -u github.com/labstack/echo/v5@096ce41d2a24f5ec652b21adbcf25c484bef49eaReacted by zuozhehao and cxlblmReacted by zuozhehao
RequestLogger: "error":"renderer not registered"
HTTPErrorHandler : err = nil