From 180976c8964dd4ffa5e57c3c70d178fd1ae5ccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Sat, 7 Feb 2026 14:38:09 +0100 Subject: [PATCH 1/2] Handle nil body from store in queue processing Store.get returns nil when the key doesn't exist. This nil was passed to Tar.unpack which called :zlib.safeInflate with a non-iodata term, causing an ArgumentError. --- lib/hexdocs/queue.ex | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/hexdocs/queue.ex b/lib/hexdocs/queue.ex index 6bfd3da..1f850c7 100644 --- a/lib/hexdocs/queue.ex +++ b/lib/hexdocs/queue.ex @@ -106,12 +106,16 @@ defmodule Hexdocs.Queue do body = Hexdocs.Store.get(:repo_bucket, key) - case type do - :upload -> - process_upload(key, repository, package, version, body, start) + if body do + case type do + :upload -> + process_upload(key, repository, package, version, body, start) - :search -> - process_search(key, repository, package, version, body, start) + :search -> + process_search(key, repository, package, version, body, start) + end + else + Logger.error("#{log_prefix} #{key}: package not found in store") end :error -> From 6f7600c09732836421ab967c7a31942c06a2ef45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Sat, 7 Feb 2026 14:43:11 +0100 Subject: [PATCH 2/2] Fix test port collision by using OS-assigned ports Using Enum.random for ports caused intermittent :eaddrinuse failures when tests ran concurrently. Use port 0 to let the OS assign a free port, then read it back with :ranch.get_port/1. --- test/hexdocs/http_test.exs | 5 ++--- test/hexdocs/plug_gs_test.exs | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/hexdocs/http_test.exs b/test/hexdocs/http_test.exs index 8a960f8..81d0310 100644 --- a/test/hexdocs/http_test.exs +++ b/test/hexdocs/http_test.exs @@ -16,9 +16,8 @@ defmodule Hexdocs.HTTPTest do end setup do - port = Enum.random(50_000..60_000) - start_supervised!({Plug.Cowboy, plug: StreamingPlug, scheme: :http, port: port}) - {:ok, port: port} + start_supervised!({Plug.Cowboy, plug: StreamingPlug, scheme: :http, port: 0}) + {:ok, port: :ranch.get_port(StreamingPlug.HTTP)} end describe "get_stream/2" do diff --git a/test/hexdocs/plug_gs_test.exs b/test/hexdocs/plug_gs_test.exs index ad8bb69..67732ba 100644 --- a/test/hexdocs/plug_gs_test.exs +++ b/test/hexdocs/plug_gs_test.exs @@ -90,8 +90,8 @@ defmodule Hexdocs.PlugGSTest do :ets.delete_all_objects(:mock_gcs_files) # Start mock GCS server - port = Enum.random(50_000..60_000) - start_supervised!({Plug.Cowboy, plug: MockGCSPlug, scheme: :http, port: port}) + start_supervised!({Plug.Cowboy, plug: MockGCSPlug, scheme: :http, port: 0}) + port = :ranch.get_port(MockGCSPlug.HTTP) # Configure to use GS store with mock server original_store_impl = Application.get_env(:hexdocs, :store_impl)