-
-
Notifications
You must be signed in to change notification settings - Fork 510
Description
Problem
When a socket error occurs in RpcClient.makeProtocolSocket, the RpcClientError is created with:
- A hardcoded generic message
"Error in socket" Cause.squash(cause)which flattens the full cause tree
This results in error messages like:
Error: RpcClientError: Error in socket at ...
The underlying socket error details (like SocketCloseError with code, closeReason, or SocketGenericError with reason: "Open" | "Read" | "Write" | "OpenTimeout") are buried in the cause field and not surfaced in the error message.
Location
https://github.com/Effect-TS/effect/blob/main/packages/rpc/src/RpcClient.ts#L1010-L1014
currentError = new RpcClientError({
reason: "Protocol",
message: "Error in socket", // <-- hardcoded, loses context
cause: Cause.squash(cause) // <-- flattens the cause tree
})Proposed Solution
Extract socket error details and include them in the message:
const socketError = Cause.failureOption(cause)
const errorMessage = Option.isSome(socketError)
? `Socket ${socketError.value.reason}${
'code' in socketError.value ? `: code ${socketError.value.code}` : ''
}${
'closeReason' in socketError.value && socketError.value.closeReason
? ` (${socketError.value.closeReason})`
: ''
}`
: "Error in socket"
currentError = new RpcClientError({
reason: "Protocol",
message: errorMessage,
cause: Cause.squash(cause)
})This would produce messages like:
Socket Close: code 1006Socket Open: connection refusedSocket OpenTimeout
Additional Consideration
The RpcClientError class itself uses the message field as a schema property, which shadows Error.message. Consider using note (or similar) for the schema field and computing get message() from the structured fields - similar to the pattern used for other tagged errors to preserve both structured data and a human-readable message.