Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions grpc/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

### Bug Fixes

* The Mint adapter now returns `{:error, %GRPC.RPCError{}}` instead of raising when a response's HTTP status is not 200, like the Gun adapter.
* The Gun adapter no longer shares a named channel's connection process across Erlang nodes. It was registered in `:global`, so a node connecting with a `:name` already used on another node adopted the remote connection process; `connect/2` returned `{:ok, channel}`, but every RPC on it then raised `ArgumentError` because `GRPC.Stub.call/5` calls `Process.alive?/1` on the connection pid and that raises for remote pids. Connection processes are now registered in the node-local `GRPC.Client.Registry`, so reuse is per node.

## v1.0.4 (2026-0-15)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,18 @@ if Code.ensure_loaded?(Mint.HTTP) do
state
end

defp process_response({:status, request_ref, 200}, state) do
State.update_response_status(state, request_ref, 200)
end

defp process_response({:status, request_ref, status}, state) do
State.update_response_status(state, request_ref, status)
state
|> State.update_response_status(request_ref, status)
|> consume_or_cancel_stream(
request_ref,
:error,
GRPC.RPCError.exception(GRPC.Status.internal(), "status got is #{status} instead of 200")
)
end

defp process_response({:headers, request_ref, headers}, state) do
Expand Down
28 changes: 28 additions & 0 deletions grpc/test/grpc/adapters/mint/connection_process_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,34 @@ defmodule GRPC.Client.Adapters.Mint.ConnectionProcessTest do
end
end

describe "handle_info - non-200 responses" do
setup :quiet_connection
setup :valid_stream_request
setup :valid_stream_response

test "reports the HTTP status to the stream response process",
%{stream_response_pid: response_pid, state: state} do
# A proxy answering with a plain HTTP error: a HEADERS frame whose only
# header is `:status` (static table index 8) with the value "502".
stream_id = state.conn.next_stream_id - 2
headers_frame = <<5::24, 0x01, 0x04, stream_id::32, 0x08, 0x03, "502">>
message = {:tcp, state.conn.socket, headers_frame}

assert {:noreply, new_state} = ConnectionProcess.handle_info(message, state)

# the connection is untouched, only this request failed
assert Mint.HTTP.open?(new_state.conn)

# the caller-facing stream response process got the status as an error
response_state = :sys.get_state(response_pid)

assert [
{:error, %GRPC.RPCError{status: 13, message: "status got is 502 instead of 200"}}
| _headers
] = :queue.to_list(response_state.responses)
end
end

describe "retry_timeout/1" do
test "returns exponentially increasing timeouts" do
t1 = ConnectionProcess.retry_timeout(1)
Expand Down
Loading