From 5024b6acba6da39988c6a83cd103a12881a20a8f Mon Sep 17 00:00:00 2001 From: Ahmed Hashim Date: Sat, 1 Aug 2026 07:54:43 -0700 Subject: [PATCH] docs: warn that predefined errors are no longer *HTTPError in v5 A v4-style custom HTTPErrorHandler that type-asserts err.(*echo.HTTPError) silently stops matching the router's predefined errors (echo.ErrNotFound, echo.ErrMethodNotAllowed, ...) in v5, because they are now immutable sentinels implementing only HTTPStatusCoder. The result is every unmatched route being rendered as a 500 instead of a 404, with no compile-time or runtime signal. Document the trap in the HTTPError section and the migration guide's error handler step, pointing at echo.StatusCode(err) as the correct replacement. --- API_CHANGES_V5.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/API_CHANGES_V5.md b/API_CHANGES_V5.md index 175c33830..0d21bea95 100644 --- a/API_CHANGES_V5.md +++ b/API_CHANGES_V5.md @@ -246,6 +246,24 @@ func (he *HTTPError) StatusCode() int // Implements HTTPStatusCoder - Added `HTTPStatusCoder` interface and `StatusCode()` method - Added `Wrap(err error)` method for error wrapping +**⚠️ Migration trap:** predefined errors such as `echo.ErrNotFound` and +`echo.ErrMethodNotAllowed` (returned by the router for unmatched routes) are no +longer `*echo.HTTPError`. They are immutable sentinels that only implement +`HTTPStatusCoder`, so a v4-style type assertion in a custom error handler stops +matching them and turns every 404/405 into a 500: + +```go +// Broken in v5: never matches echo.ErrNotFound +if he, ok := err.(*echo.HTTPError); ok { + code = he.Code +} else { + code = http.StatusInternalServerError +} + +// Correct: works for *HTTPError and the predefined errors +code := echo.StatusCode(err) // 0 if err carries no status +``` + --- ### 7. **HTTPErrorHandler Signature Changed**