Skip to content

fix(router): grow PathValues for contexts created before a route with more params - #3157

Merged
vishr merged 3 commits into
masterfrom
fix/router-late-route-path-values
Oct 6, 2026
Merged

vishr merged 3 commits into
masterfrom
fix/router-late-route-path-values

Conversation

@vishr

@vishr vishr commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Adding a route with more path params after Echo has served requests panics with index out of range [0] with length 0 on the next request that matches it. This happens with both DefaultRouter and ConcurrentRouter, even though NewConcurrentRouter says routes can be added after the server has started. The faulty line is in every v5 release (v5.0.0 through v5.4.0).

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

Cause: pooled Contexts keep the PathValues capacity they were created with. DefaultRouter.Route already detected the short capacity, but it allocated a zero-length slice (make(PathValues, 0, max)) and then set values by index. The same branch is reached by Contexts created without an Echo and when routes are added through Router().Add directly; both panic on master too.

Fix: grow the Context's PathValues at full length in that existing branch. The Context keeps the new slice, so it is grown once, whatever route the request matches (static, param, 404 or 405), until a route with even more params is added. The Router contract comment now says that Route must handle a Context with a smaller capacity, and that adding routes through Echo is what keeps Contexts sized up front.

Cost: the change only touches the branch that already handled short capacity, so steady state is unchanged:

  • ServeHTTP_*, Echo*API and Router*API benchmarks: 20 interleaved rounds against master show no regression, and allocations per operation are unchanged.
  • After its first request, a stale Context allocates the same as a fresh one for static, 404, 405 and param routes. On master, when routes have 2 or more params, a stale Context serving static or 404 requests allocated one slice per request indefinitely.

Tests:

  • TestDefaultRouter_RouteWithContextCreatedBeforeParamRouteAdded is deterministic. It covers param/any, static and not-found cases on a Context created before the routes were added, and checks values and kept capacity. On master the param case panics, and the static and not-found cases fail the capacity check.
  • TestEcho_AddParamRouteAfterServing covers the end-to-end repro on the default and concurrent routers. It depends on sync.Pool returning the same Context, which -race sometimes does not.
  • The race suite passes. A separate concurrent add-while-serving stress run on ConcurrentRouter was clean; it is not committed.

Refs #1705 (the same root cause, reported in 2020).

vishr added 3 commits October 5, 2026 14:49
… more params

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, with both
DefaultRouter and ConcurrentRouter. Pooled Contexts keep the PathValues
capacity they were created with. DefaultRouter.Route already detected the
short capacity, but allocated a zero-length slice and then set values by
index.

Grow the Context's PathValues at full length instead. The Context keeps the
new slice, so later requests through it do not grow it again. Document in
the Router contract that Route must handle such Contexts.

Refs #1705
Address review nits: the grow branch also covers Contexts created without
an Echo and routes added through Router directly, the Router contract
explains why routes should be added through Echo, and the regression test
sits with the other PathValues tests.
@vishr
vishr requested a balanced review from Copilot October 6, 2026 02:47

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 correctly addresses the panic and is covered by deterministic and integration-level regression tests.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes stale pooled contexts panicking after routes with additional path parameters are registered.

Changes:

  • Grows PathValues to an indexable length when capacity is insufficient.
  • Documents the router capacity contract.
  • Adds deterministic and end-to-end regression tests.
File Description
router.go Fixes PathValues growth and updates the router contract.
router_test.go Tests stale contexts across route outcomes.
echo_test.go Tests route addition after serving requests.

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

@vishr
vishr merged commit 4f7bea5 into master Oct 6, 2026
12 checks passed
@vishr
vishr deleted the fix/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