Skip to content

fix(platform): preserve fiber context in HttpLayerRouter.addHttpApi so API-level middleware is applied#6147

Open
syhstanley wants to merge 2 commits intoEffect-TS:mainfrom
syhstanley:fix/httplayerrouter-api-middleware-skipped
Open

fix(platform): preserve fiber context in HttpLayerRouter.addHttpApi so API-level middleware is applied#6147
syhstanley wants to merge 2 commits intoEffect-TS:mainfrom
syhstanley:fix/httplayerrouter-api-middleware-skipped

Conversation

@syhstanley
Copy link

Summary

Fixes #6121@effect/platform HttpApi: middleware is skipped when using HttpLayerRouter.addHttpApi with multiple APIs combined via Layer.mergeAll.

Root Cause

In HttpLayerRouter.addHttpApi, each route handler was wrapped with:

handler: Effect.provide(route.handler, context)

Effect.provide calls fiberRefLocally(currentContext, context) which replaces the entire fiber context with the captured build-time context. This silently discards any services injected at request time — most notably the Session service provided by API-level HttpApiMiddleware via Effect.provideServiceEffect.

Fix

Replace Effect.provide with Effect.mapInputContext to merge the build-time platform services into the runtime fiber context instead of replacing it:

handler: Effect.mapInputContext(route.handler, (input) => Context.merge(context, input))

This preserves all request-time services (including Session from API-level middleware) while still ensuring the required platform services (Etag, FileSystem, HttpPlatform, Path, HttpRouter) are available. This is the same pattern already used by HttpApiBuilder.group internally.

Symptoms Fixed

  • Endpoints returning 200 instead of 401 when rejecting middleware was configured (middleware was silently skipped for APIs after the first in Layer.mergeAll)
  • Endpoints returning 500 "Service not found: Session" when accepting middleware was configured (Session injected by middleware was overwritten before the handler ran)

Tests

Adds packages/platform-node/test/HttpApiLayerRouterMiddleware.test.ts with 5 regression tests covering:

  1. ✅ Protected endpoint returns 401 (not 200) with rejecting middleware
  2. ✅ Session-using endpoint returns 401 (not 500) with rejecting middleware
  3. ✅ External API routes remain accessible without authentication
  4. ✅ Protected endpoint returns 200 with accepting middleware
  5. ✅ Session service is injected and accessible in handler with accepting middleware

Test plan

🤖 Generated with Claude Code

When `HttpLayerRouter.addHttpApi` wrapped route handlers using
`Effect.provide(route.handler, context)`, it replaced the entire
fiber context (via `fiberRefLocally`). This silently discarded any
services injected at runtime — most notably `Session` provided by
API-level `HttpApiMiddleware` via `provideServiceEffect`.

The bug manifested as:
- Endpoints returning 200 instead of 401 when rejecting middleware
  was configured (middleware was skipped entirely for the second
  API in `Layer.mergeAll`)
- Endpoints returning 500 "Service not found: Session" when
  accepting middleware was configured (Session injected by middleware
  was overwritten before the handler ran)

Fix: replace `Effect.provide` with `Effect.mapInputContext` so the
build-time platform services context is *merged* into the runtime
fiber context rather than replacing it. This preserves all
request-time services (including Session from API-level middleware).

Adds regression tests for GitHub issue Effect-TS#6121.

Fixes Effect-TS#6121

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@syhstanley syhstanley requested a review from tim-smart as a code owner March 26, 2026 12:02
@github-project-automation github-project-automation bot moved this to Discussion Ongoing in PR Backlog Mar 26, 2026
@changeset-bot
Copy link

changeset-bot bot commented Mar 26, 2026

🦋 Changeset detected

Latest commit: 5fd07e0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 31 packages
Name Type
@effect/platform Patch
@effect/cli Patch
@effect/cluster Patch
@effect/experimental Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/rpc Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-drizzle Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-node Patch
@effect/sql Patch
@effect/workflow Patch
@effect/ai Patch
@effect/ai-amazon-bedrock Patch
@effect/ai-anthropic Patch
@effect/ai-google Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/sql-kysely Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

@effect/platform HttpApi: middleware is skipped

2 participants