diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc
index fc53a40f44187616a178d4f97225bb1ebe60c7c5..6a6280566efac316fdb74c18cacaa67de53ade04 100644
--- a/src/box/lua/error.cc
+++ b/src/box/lua/error.cc
@@ -154,6 +154,16 @@ luaT_error_clear(lua_State *L)
 	return 0;
 }
 
+static int
+luaT_error_set(struct lua_State *L)
+{
+	if (lua_gettop(L) == 0)
+		return luaL_error(L, "Usage: box.error.set(error)");
+	struct error *e = luaL_checkerror(L, 1);
+	diag_set_error(&fiber()->diag, e);
+	return 0;
+}
+
 static int
 lbox_errinj_set(struct lua_State *L)
 {
@@ -268,6 +278,10 @@ box_lua_error_init(struct lua_State *L) {
 			lua_pushcfunction(L, luaT_error_new);
 			lua_setfield(L, -2, "new");
 		}
+		{
+			lua_pushcfunction(L, luaT_error_set);
+			lua_setfield(L, -2, "set");
+		}
 		lua_setfield(L, -2, "__index");
 	}
 	lua_setmetatable(L, -2);
diff --git a/src/lua/error.c b/src/lua/error.c
index d82e78dc475dc8197675ec5ec7b5183001b5f5b0..18a990a888117b4f197f81bff403412181d7d363 100644
--- a/src/lua/error.c
+++ b/src/lua/error.c
@@ -53,7 +53,7 @@ luaL_iserror(struct lua_State *L, int narg)
 	return e;
 }
 
-static struct error *
+struct error *
 luaL_checkerror(struct lua_State *L, int narg)
 {
 	struct error *error = luaL_iserror(L, narg);
diff --git a/src/lua/error.h b/src/lua/error.h
index 64fa5eba3621ed32da2c82793250c2dd36e2974c..16cdaf7fe1b890110db26320dd26c0f6421d4aee 100644
--- a/src/lua/error.h
+++ b/src/lua/error.h
@@ -65,6 +65,9 @@ luaT_pusherror(struct lua_State *L, struct error *e);
 struct error *
 luaL_iserror(struct lua_State *L, int narg);
 
+struct error *
+luaL_checkerror(struct lua_State *L, int narg);
+
 void
 tarantool_lua_error_init(struct lua_State *L);
 
diff --git a/test/box/error.result b/test/box/error.result
index 9b6c8b4628063e0018682abc40763954d415b78f..31b2ce52becc8196da667fbfab93c3d5fb1fffee 100644
--- a/test/box/error.result
+++ b/test/box/error.result
@@ -436,6 +436,42 @@ test_run:cmd("setopt delimiter ''");
  | ---
  | - true
  | ...
+
+-- gh-4778: don't add created via box.error.new() errors to
+-- Tarantool's diagnostic area.
+--
+err = box.error.new({code = 111, reason = "cause"})
+ | ---
+ | ...
+assert(box.error.last() ~= err)
+ | ---
+ | - error: assertion failed!
+ | ...
+box.error.set(err)
+ | ---
+ | ...
+assert(box.error.last() == err)
+ | ---
+ | - true
+ | ...
+-- Consider wrong or tricky inputs to box.error.set()
+--
+box.error.set(1)
+ | ---
+ | - error: 'Invalid argument #1 (error expected, got number)'
+ | ...
+box.error.set(nil)
+ | ---
+ | - error: 'Invalid argument #1 (error expected, got nil)'
+ | ...
+box.error.set(box.error.last())
+ | ---
+ | ...
+assert(box.error.last() == err)
+ | ---
+ | - true
+ | ...
+
 space:drop()
  | ---
  | ...
diff --git a/test/box/error.test.lua b/test/box/error.test.lua
index d16cc5672984f75b3d67e1e2cac12230135d5e19..81591ea7e7400d024c2e3a470376e724daf94715 100644
--- a/test/box/error.test.lua
+++ b/test/box/error.test.lua
@@ -77,4 +77,19 @@ end;
 t;
 
 test_run:cmd("setopt delimiter ''");
+
+-- gh-4778: don't add created via box.error.new() errors to
+-- Tarantool's diagnostic area.
+--
+err = box.error.new({code = 111, reason = "cause"})
+assert(box.error.last() ~= err)
+box.error.set(err)
+assert(box.error.last() == err)
+-- Consider wrong or tricky inputs to box.error.set()
+--
+box.error.set(1)
+box.error.set(nil)
+box.error.set(box.error.last())
+assert(box.error.last() == err)
+
 space:drop()