RpcServer: with disableFatalDefects, a handler that throws before returning its Effect still fails every pending call
Los mantenedores suelen responder en 1 día
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
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de Effect-TS/effect
-
RpcTest.makeClient: accept disableFatalDefectsPosiblemente ocupada @effect-bot la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Effect-TS/effect#9893 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
-
`HttpApiSchema.Upgrade`: allow a regular success for servers that don't upgradePosiblemente ocupada @effect-bot la tomó hoy. Abiertodocker-made-me-do-it enhancement
Effect-TS/effect#9912 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
docker-made-me-do-it enhancement
Dificultad 5/5 Más de una semana Aptitud para principiantes 20/100
Los mantenedores suelen responder en 1 día
-
`HttpApiSchema`: stream bodies in a custom framingPosiblemente ocupada @effect-bot la tomó hoy. Abiertodocker-made-me-do-it enhancement
Effect-TS/effect#9910 · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
`HttpApiSchema` streams: declare every media type a stream can be sent asPosiblemente ocupada @effect-bot la tomó hoy. Abiertodocker-made-me-do-it enhancement
Effect-TS/effect#9909 · 1 asignado ·
Los mantenedores suelen responder en 1 día
Todos los issues de Effect-TS/effect
Issues similares
-
[Bug]: Device screenshot fails with 500 on iPhone Duo (Xcode 27.2): serve-sim calls simctl without --displayPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
pingdotgg/t3code#24900 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
inu-appcenter/UNIDorm-web#411 ·
Los mantenedores suelen responder en 1 día
-
🐛 bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
ranxianglei/billion-context#4720 ·
Los mantenedores suelen responder en 1 día
-
area:arcade game p3-medium ready-for-agent type:bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
fderuiter/deruiter.dev#2840 ·
Los mantenedores suelen responder en 1 día