`FunctionClauseError` due to mismatch of `ref` argument in `Req.Steps.finch_parse_message/2`
crkent opened this issue · comments
System details
Req version: 0.5.0
Elixir version: 1.16.3
OTP version: 26
OS: macOS 14.5
Issue
Collecting the following Stream
(edited from an original form to provide minimal context) results in the following FunctionClauseError
within the Req.Steps
module (message is redacted, slightly, to protect the innocent).
Stream.resource(
fn -> {Req.get!(request, into: :self), {[], 0}} end,
fn
:halt -> {:halt, nil}
{response, {acc, byte_size}} ->
case Req.parse_message(response, receive do message -> message end) do
{:ok, [{:data, data}]} ->
acc = [data | acc]
byte_size = :erlang.iolist_size(data) + byte_size
if(byte_size > 5_000_000, do: {[acc], {response, {[], 0}}}, else: {[], {response, {acc, byte_size}}})
{:ok, [:done]} -> {[acc], :halt}
{:error, reason} -> raise "Error"
end
end,
fn _ -> nil end
)
** (FunctionClauseError) no function clause matching in Req.Steps.finch_parse_message/2
The following arguments were given to Req.Steps.finch_parse_message/2:
# 1
{Finch.HTTP1.Pool, #PID<0.1532.0>}
# 2
{{Finch.HTTP1.Pool, #PID<0.1339.0>},
{:data, "<REDACTED>"}}
Attempted function clauses (showing 4 out of 4):
defp finch_parse_message(ref, {ref, {:data, data}})
defp finch_parse_message(ref, {ref, :done})
defp finch_parse_message(ref, {ref, {:trailers, trailers}})
defp finch_parse_message(ref, {ref, {:error, reason}})
(req 0.5.0) Req.Steps.finch_parse_message/2
...
...
It appears that the match error is due to some impurity in the way that the ref
argument to Req.Steps.finch_parse_message/2
is obtained. This impurity appears to result in a difference between the two PIDs.
Expected behaviour
I believe that, when collected within a single process, the following Stream
should run without error.
Thank you for the report. This is very unexpected indeed. If you have a way to reproduce it, it would be a great help, ideally a "Mix.install script" with Req and, say, Bandit.
Thank you for the report. This is very unexpected indeed. If you have a way to reproduce it, it would be a great help, ideally a "Mix.install script" with Req and, say, Bandit.
Minimal reproducible example
I omitted Bandit and used a simple url that is utilized in the Req
documentation.
Setup
Mix.install([{:req, "== 0.5.1"}])
Error producing evaluation
request =
Req.new(
url: "https://github.com/elixir-lang/elixir/releases/download/v1.15.4/elixir-otp-26.zip"
)
resource =
Stream.resource(
fn -> {Req.get!(request, into: :self), {[], 0}} end,
fn
:halt ->
{:halt, nil}
{response, {acc, byte_size}} ->
case Req.parse_message(
response,
receive do
message -> message
end
) do
{:ok, [{:data, data}]} ->
acc = [data | acc]
byte_size = :erlang.iolist_size(data) + byte_size
if(byte_size > 5_000_000,
do: {[acc], {response, {[], 0}}},
else: {[], {response, {acc, byte_size}}}
)
{:ok, [:done]} ->
{[acc], :halt}
{:error, reason} ->
raise "Error"
end
end,
fn _ -> nil end
)
resource |> Enum.take(1)
Output
12:35:45.065 [debug] redirecting to https://objects.githubusercontent.com/github-production-release-asset-2e65be/1234714/35ca722a-7fc3-402e-8636-532b07322a9e?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20240627%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240627T183545Z&X-Amz-Expires=300&X-Amz-Signature=d831212fe78d04b391002ebddd33ac99bf43f420918793ccd8eb6c99759bccda&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=1234714&response-content-disposition=attachment%3B%20filename%3Delixir-otp-26.zip&response-content-type=application%2Foctet-stream
** (FunctionClauseError) no function clause matching in Req.Steps.finch_parse_message/2
The following arguments were given to Req.Steps.finch_parse_message/2:
# 1
{Finch.HTTP1.Pool, #PID<0.1066.0>}
# 2
{{Finch.HTTP1.Pool, #PID<0.1041.0>},
{:data,
<<80, 75, 3, 4, 10, 0, 0, 0, 0, 0, 81, 78, 242, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 28,
0, 98, 105, 110, 47, 85, 84, 9, 0, 3, 106, 96, 182, 100, 128, 96, 182, ...>>}}
Attempted function clauses (showing 4 out of 4):
defp finch_parse_message(ref, {ref, {:data, data}})
defp finch_parse_message(ref, {ref, :done})
defp finch_parse_message(ref, {ref, {:trailers, trailers}})
defp finch_parse_message(ref, {ref, {:error, reason}})
(req 0.5.1) lib/req/steps.ex:1013: Req.Steps.finch_parse_message/2
#cell:amhewdr7w47z3ujd:8: (file)
#cell:amhewdr7w47z3ujd:1: (file)
Thank you for reproduction, it was extremely helpful. I just submitted fix to main, could you give it a go?
Works perfectly! Thank you!