diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js
index 071a80abaf0..4bdfbc4c224 100644
--- a/addons/web/static/src/views/relational_model.js
+++ b/addons/web/static/src/views/relational_model.js
@@ -3503,6 +3503,17 @@ export class RelationalModel extends Model {
) {
rootParams.groupBy = [this.defaultGroupBy];
}
+
+ if (rootParams.context) {
+ // *_view_ref and search_default_* context keys are not destined to us, rather
+ // they were tyîcally "consumed" by the View.
+ // The default_* context keys are, on the contrary, destined for us.
+ rootParams.context = Object.fromEntries(
+ Object.entries(rootParams.context).filter(
+ ([key]) => !key.endsWith("_view_ref") && !key.startsWith("search_default_")
+ )
+ );
+ }
rootParams.rawContext = {
make: () => {
return makeContext([rootParams.context], {});
diff --git a/addons/web/static/tests/views/list_view_tests.js b/addons/web/static/tests/views/list_view_tests.js
index 8240d64beae..930a7c11d25 100644
--- a/addons/web/static/tests/views/list_view_tests.js
+++ b/addons/web/static/tests/views/list_view_tests.js
@@ -12,6 +12,7 @@ import { uiService } from "@web/core/ui/ui_service";
import { getNextTabableElement } from "@web/core/utils/ui";
import { session } from "@web/session";
import { FloatField } from "@web/views/fields/float/float_field";
+import { AutoComplete } from "@web/core/autocomplete/autocomplete";
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
import { textField } from "@web/views/fields/text/text_field";
import { ListController } from "@web/views/list/list_controller";
@@ -18837,4 +18838,78 @@ QUnit.module("Views", (hooks) => {
"onchange result should be applied"
);
});
+
+ QUnit.test("context keys not passed down the stack and not to fields", async (assert) => {
+ patchWithCleanup(AutoComplete, {
+ timeout: 0,
+ });
+ serverData.actions = {
+ 1: {
+ id: 1,
+ name: "Foo",
+ res_model: "foo",
+ type: "ir.actions.act_window",
+ views: [[false, "list"]],
+ context: {
+ tree_view_ref: "foo_view_ref",
+ search_default_bar: true,
+ },
+ },
+ };
+ serverData.views = {
+ "foo,foo_view_ref,list": `
+
+
+ `,
+ "foo,false,search": "",
+ "bar,false,list": ``,
+ "bar,false,search": "",
+ };
+
+ const barRecs = [];
+ for (let i = 1; i < 50; i++) {
+ barRecs.push({
+ id: i,
+ display_name: `Value ${i}`,
+ });
+ }
+ serverData.models.bar.records = barRecs;
+
+ const mockRPC = (route, args) => {
+ if (args.method) {
+ assert.step(
+ `${args.model}: ${args.method}: ${JSON.stringify(args.kwargs.context)}`
+ );
+ }
+ };
+ const wc = await createWebClient({ serverData, mockRPC });
+ await doAction(wc, 1);
+ assert.verifySteps([
+ `foo: get_views: {"lang":"en","uid":7,"tz":"taht","tree_view_ref":"foo_view_ref","search_default_bar":true}`,
+ `foo: web_search_read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`,
+ `bar: read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`,
+ ]);
+
+ await click(target.querySelectorAll(".o_data_row .o_data_cell")[1]);
+
+ const input = target.querySelector(".o_selected_row .o_field_many2many_tags input");
+ await triggerEvent(input, null, "focus");
+ await click(input);
+ await nextTick();
+ assert.verifySteps([`bar: name_search: {"lang":"en","uid":7,"tz":"taht"}`]);
+
+ const items = Array.from(
+ target.querySelectorAll(".o_selected_row .o_field_many2many_tags .dropdown-item")
+ );
+ await click(items.find((el) => el.textContent.trim() === "Search More..."));
+ assert.verifySteps([
+ `bar: get_views: {"lang":"en","uid":7,"tz":"taht"}`,
+ `bar: web_search_read: {"lang":"en","uid":7,"tz":"taht","bin_size":true}`,
+ ]);
+ assert.containsOnce(target, ".modal");
+ assert.strictEqual(
+ target.querySelector(".modal .modal-header .modal-title").textContent,
+ "Search: M2M field"
+ );
+ });
});