Skip to content

fix(router): grow param values for contexts created before a route with more params (v4) - #3158

Merged
vishr merged 2 commits into
v4from
fix/v4-router-late-route-path-values
Oct 6, 2026
Merged

vishr merged 2 commits into
v4from
fix/v4-router-late-route-path-values

Conversation

@vishr

@vishr vishr commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Adding a route with path params after Echo has served requests can panic with index out of range [0] with length 0. It happens in sequential, single-goroutine use:

  • A late any route (/files/*) panics in every v4 release: in Router.Find, or already in Context.Reset from v4.1.12 to v4.11.x.
  • A late param route (/users/:id) wrongly returned 404 up to v4.1.11. From v4.1.12 to v4.11.x it panics in Context.Reset, on the next request of any kind.
  • From v4.12.0 (after Remove maxparam dependence from Context #2611), late param and any routes panic in Router.Find, on requests whose routing reaches the late param or any node. That includes some 404s and 405s.

Repro: register GET /static, serve /static, register GET /users/:id, serve /users/42.

Cause: pooled contexts keep the pvalues length they were created with (*e.maxParam at the time), and Router.Find sets values by index. #2611 fixed SetParamNames/SetParamValues and Reset, but not Find.

Fix: when Find is about to set a param or any value past the context's pvalues length, it grows the slice to *r.echo.maxParam, keeps the values already set, and stores it on the context. Static routes never reach these branches.

This does not make it safe to add routes concurrently with serving. That is still unsupported in v4, as discussed in #1705.

Cost: 20 interleaved rounds against v4 show +0.9% geomean on router benchmarks, with 0 allocs. Static routes are unchanged. Param-heavy routes rise up to about +2.8%, which is about 0.5–1.4 ns per param lookup. This was the cheapest of three placements measured (top of Find: +1.1%; Reset with clear(): +2.6%).

Tests:

  • TestEchoAddParamRouteAfterServing is the end-to-end repro.
  • TestRouterFindWithContextCreatedBeforeParamRouteAdded covers a param route and an any route on a context created before the routes were added; each case covers one grow branch.
  • Both panic on v4 without the fix, and the race suite passes.

Refs #1705

vishr added 2 commits October 5, 2026 14:56
…th more params (v4)

Adding a route with more path params after Echo has served requests panics
with "index out of range" on the next request that matches it. Pooled
contexts keep the pvalues length they were created with, and Router.Find
sets values by index.

Grow the context's pvalues when Find is about to set a value past its
length. Static routes do not reach these branches. The context keeps the
new slice, so later requests through it do not grow it again.

Refs #1705
@vishr
vishr requested a balanced review from Copilot October 6, 2026 02:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused fix preserves routing state and has appropriate regression coverage for both growth paths.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes stale pooled contexts so routes added later with more path parameters no longer panic.

Changes:

  • Dynamically grows context parameter storage during router lookup.
  • Preserves captured values during growth.
  • Adds router-level and end-to-end regression tests.
File Description
router.go Grows parameter storage in param and wildcard branches.
router_test.go Tests stale contexts against late param and wildcard routes.
echo_test.go Tests the reported pooled-context scenario end to end.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@vishr
vishr merged commit be08005 into v4 Oct 6, 2026
9 checks passed
@vishr
vishr deleted the fix/v4-router-late-route-path-values branch October 6, 2026 02:52
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.

2 participants