You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2026/03/26 22:23:24 UTC

(couchdb) 01/01: Handle a bad_request triple in fabric_doc_update

This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch handle-bad-request-triple
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 14bfd33ca0503c79f63352250de76e5a223fde88
Author: Nick Vatamaniuc <va...@gmail.com>
AuthorDate: Thu Mar 26 18:16:08 2026 -0400

    Handle a bad_request triple in fabric_doc_update
    
    Besides the `{bad_request, Msg}` also handle the `{bad_request, Error,
    Reason}` triple.  Design document validator can return those [1], for  instance.
    
    While at it add a test to cover both the tuple and the triple case.
    
    [1] https://github.com/apache/couchdb/blob/997deea76f4489e2e8702bb7dbf50eceffdd5650/src/couch/src/couch_db.erl#L984-L986
---
 src/fabric/src/fabric_doc_update.erl | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/fabric/src/fabric_doc_update.erl b/src/fabric/src/fabric_doc_update.erl
index 7f3e2095c..89fb9618d 100644
--- a/src/fabric/src/fabric_doc_update.erl
+++ b/src/fabric/src/fabric_doc_update.erl
@@ -148,6 +148,8 @@ handle_message({not_found, no_db_file} = X, Worker, #acc{} = Acc0) ->
     handle_message({ok, [X || _D <- Docs]}, Worker, Acc0);
 handle_message({bad_request, Msg}, _, _) ->
     throw({bad_request, Msg});
+handle_message({bad_request, Error, Reason}, _, _) ->
+    throw({bad_request, Error, Reason});
 handle_message({forbidden, Msg}, _, _) ->
     throw({forbidden, Msg});
 handle_message({request_entity_too_large, Entity}, _, _) ->
@@ -484,7 +486,8 @@ doc_update_test_() ->
             fun other_errors_one_forbid/0,
             fun one_error_two_forbid/0,
             fun one_success_two_forbid/0,
-            fun worker_before_doc_update_forbidden/0
+            fun worker_before_doc_update_forbidden/0,
+            fun handle_bad_request/0
         ]
     }.
 
@@ -965,6 +968,28 @@ worker_before_doc_update_forbidden() ->
     },
     ?assertThrow({forbidden, <<"msg">>}, handle_message({forbidden, <<"msg">>}, hd(Shards), Acc)).
 
+handle_bad_request() ->
+    Doc1 = #doc{revs = {1, [<<"foo">>]}},
+    Docs = [Doc1],
+    Shards =
+        mem3_util:create_partition_map("foo", 3, 1, ["node1", "node2", "node3"]),
+    GroupedDocs = group_docs_by_shard_hack(<<"foo">>, Shards, Docs),
+    Acc = #acc{
+        waiting_count = length(Shards),
+        doc_count = length(Docs),
+        w = 2,
+        grouped_docs = GroupedDocs,
+        reply = dict:from_list([{Doc, []} || Doc <- Docs])
+    },
+    ?assertThrow(
+        {bad_request, msg},
+        handle_message({bad_request, msg}, hd(Shards), Acc)
+    ),
+    ?assertThrow(
+        {bad_request, err, reason},
+        handle_message({bad_request, err, reason}, hd(Shards), Acc)
+    ).
+
 % needed for testing to avoid having to start the mem3 application
 group_docs_by_shard_hack(_DbName, Shards, Docs) ->
     dict:to_list(