Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

RpcServer: with disableFatalDefects, a handler that throws before returning its Effect still fails every pending call

Abierto
#9,892 0 comentarios 0 reacciones 1 asignado Ver en GitHub

Los mantenedores suelen responder en 1 día

@effect-bot ya está trabajando en esto.

Desde el 24/10/2026.

  • #9899 de @effect-bot — abierto

Evaluación

Este issue todavía no se ha evaluado.

Descripción

Written by an AI agent (Claude) on behalf of @jasonkuhrt.

What version of Effect is running?

4.0.4 (Node 24). The code involved is unchanged on main (53823f2, 4.0.6).

What steps can reproduce the bug?

A server built with disableFatalDefects: true, one call in flight, and a second call whose handler throws before it returns an Effect:

import { Deferred, Effect, Exit, Fiber, Schema } from "effect"
import { Rpc, RpcClient, RpcGroup, RpcServer } from "effect/rpc"

const Rpcs = RpcGroup.make(
  Rpc.make("Pending", { success: Schema.String }),
  Rpc.make("Throws", { success: Schema.String })
)

const program = Effect.gen(function*() {
  const started = yield* Deferred.make<void>()
  const release = yield* Deferred.make<string>()
  const handlers = Rpcs.toLayer({
    Pending: () => Effect.andThen(Deferred.succeed(started, undefined), Deferred.await(release)),
    Throws: (): Effect.Effect<string> => {
      throw new Error("thrown before returning an Effect")
    }
  })
  yield* Effect.gen(function*() {
    let client!: Effect.Success<ReturnType<typeof RpcClient.makeNoSerialization<RpcGroup.Rpcs<typeof Rpcs>, never>>>
    const server = yield* RpcServer.makeNoSerialization(Rpcs, {
      disableFatalDefects: true,
      onFromServer: (response) => client.write(response)
    })
    client = yield* RpcClient.makeNoSerialization(Rpcs, {
      supportsAck: true,
      onFromClient: ({ message }) => server.write(0, message)
    })
    const pending = yield* Effect.forkChild(client.client.Pending())
    yield* Deferred.await(started)
    const threw = yield* Effect.exit(client.client.Throws())
    yield* Deferred.succeed(release, "still served")
    const pendingExit = yield* Effect.exit(Fiber.join(pending))
    console.log("Throws:", Exit.isFailure(threw) ? "failed" : "succeeded")
    console.log("Pending:", Exit.isSuccess(pendingExit) ? `succeeded with ${pendingExit.value}` : `failed: ${pendingExit.cause}`)
  }).pipe(Effect.provide(handlers))
}).pipe(Effect.scoped)

Effect.runPromise(program)
What is the expected behavior?

The throw fails the Throws call alone, as an Exit.die, and Pending still succeeds. That is what happens when the handler returns Effect.die(...) instead of throwing:

Throws: failed
Pending: succeeded with still served
What do you see instead?

Pending fails with the error Throws's handler threw:

Throws: failed
Pending: failed: Cause([Die(Error: thrown before returning an Effect)])
Additional information

RpcServer.makeNoSerialization calls entry.handler(request.payload, metadata) (packages/effect/src/rpc/RpcServer.ts:281 on main) before the request's own exit handling, which is the only place disableFatalDefects is read (:328). A synchronous throw from the handler reaches the message loop's outer catch, and sendDefect answers the whole client with a connection-level Defect, so the client fails every pending call.

Turning a throw from entry.handler(...) into that request's Exit.die, through the same disableFatalDefects branch, would fix it.

Related: #9212, the client-side half, fixed in #9232.

Lenguaje dominante
TypeScript
Estrellas
16.7k
Forks
808
Merge medio
10 h 33 min
PR fusionados (30 d)
830

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de Effect-TS/effect

Todos los issues de Effect-TS/effect

Issues similares

Más issues de TypeScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.