@@ -154,6 +154,97 @@ defmodule Test.Acceptance.GetRelatedTest do
154154 :ok
155155 end
156156
157+ describe "GET /:id with invalid filter and includes" do
158+ test "returns JSON:API error document instead of crashing with KeyError" do
159+ # Create a post with comments
160+ post =
161+ Post
162+ |> Ash.Changeset . for_create ( :create , % { name: "John Doe" , content: "Test post" } )
163+ |> Ash . create! ( )
164+
165+ _comment =
166+ Comment
167+ |> Ash.Changeset . for_create ( :create , % {
168+ name: "Test comment" ,
169+ content: "comment" ,
170+ post_id: post . id
171+ } )
172+ |> Ash . create! ( )
173+
174+ # This request triggers a filter error in fetch_record_from_path when the ID
175+ # format is invalid. The bug would cause a KeyError because fetch_record_from_path
176+ # returned {:error, request} instead of just request, and chain/3 would try to
177+ # access request.errors on the tuple.
178+ #
179+ # With the fix, this returns a proper 404 error document
180+ response =
181+ Domain
182+ |> get ( "/posts/invalid-id-format/comments?include=post" , status: 404 )
183+
184+ # Verify we get a proper JSON:API error response, not a crash
185+ assert is_map ( response . resp_body )
186+ assert Map . has_key? ( response . resp_body , "errors" )
187+ errors = response . resp_body [ "errors" ]
188+ assert is_list ( errors )
189+ assert length ( errors ) > 0
190+
191+ # Verify the error has proper JSON:API structure
192+ error = hd ( errors )
193+ assert is_map ( error )
194+ assert Map . has_key? ( error , "code" )
195+ assert Map . has_key? ( error , "title" )
196+ assert Map . has_key? ( error , "detail" )
197+ assert Map . has_key? ( error , "status" )
198+
199+ # The key point: we got a proper error response (404), not a 500 crash
200+ assert error [ "status" ] == "404"
201+ assert error [ "code" ] == "not_found"
202+ end
203+
204+ test "returns JSON:API error for non-existent ID with includes" do
205+ # Use a valid UUID format but non-existent ID
206+ non_existent_id = Ash.UUID . generate ( )
207+
208+ response =
209+ Domain
210+ |> get ( "/posts/#{ non_existent_id } /comments?include=post" , status: 404 )
211+
212+ # Verify we get a proper 404 JSON:API error response
213+ assert is_map ( response . resp_body )
214+ assert Map . has_key? ( response . resp_body , "errors" )
215+ errors = response . resp_body [ "errors" ]
216+ assert is_list ( errors )
217+ assert length ( errors ) > 0
218+
219+ error = hd ( errors )
220+ assert error [ "status" ] == "404"
221+ assert error [ "code" ] == "not_found"
222+ end
223+
224+ test "handles non-existent ID with complex includes gracefully" do
225+ # Use a non-existent ID to trigger the error path in fetch_record_from_path
226+ # This exercises the code path where the lookup fails and we need to add an error
227+ non_existent_id = Ash.UUID . generate ( )
228+
229+ # Before the fix, this would crash with KeyError when chain/3 tried to access
230+ # request.errors on {:error, request}. After the fix, it returns proper 404.
231+ response =
232+ Domain
233+ |> get ( "/posts/#{ non_existent_id } /comments?include=post" , status: 404 )
234+
235+ # Should return error document, not crash
236+ assert is_map ( response . resp_body )
237+ assert Map . has_key? ( response . resp_body , "errors" )
238+ errors = response . resp_body [ "errors" ]
239+ assert is_list ( errors )
240+ assert length ( errors ) > 0
241+
242+ error = hd ( errors )
243+ assert error [ "status" ] == "404"
244+ assert error [ "code" ] == "not_found"
245+ end
246+ end
247+
157248 describe "index endpoint" do
158249 setup do
159250 post =
0 commit comments