diff --git a/src/main.rs b/src/main.rs
index 55c61c424b1cfdb55c8936e0078a18a24fe4d512..1cfdc2886b048d4520fba96b03dc463fe1b11644 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -97,10 +97,12 @@ fn picolib_setup(args: &args::Run) {
         tlua::function2(
             |x: String, opts: Option<ProposeEvalOpts>| -> Result<(), Error> {
                 let timeout = opts.and_then(|opts| opts.timeout).unwrap_or(10.0);
-                traft::node::global()?.propose(
-                    traft::Op::EvalLua { code: x },
-                    Duration::from_secs_f64(timeout),
-                )
+                traft::node::global()?
+                    .propose(
+                        traft::OpEvalLua { code: x },
+                        Duration::from_secs_f64(timeout),
+                    )
+                    .and_then(|res| res.map_err(Into::into))
             },
         ),
     );
diff --git a/src/tarantool.rs b/src/tarantool.rs
index db6beefde0f14744342628d806983c17581299ef..c3cf4d5d141bad36050eeb43cc7b7b156820c659 100644
--- a/src/tarantool.rs
+++ b/src/tarantool.rs
@@ -5,7 +5,7 @@ use std::time::Instant;
 use ::tarantool::fiber;
 use ::tarantool::lua_state;
 use ::tarantool::net_box;
-use ::tarantool::tlua::{self, LuaFunction, LuaTable};
+use ::tarantool::tlua::{self, LuaError, LuaFunction, LuaTable};
 pub use ::tarantool::trigger::on_shutdown;
 use ::tarantool::tuple::AsTuple;
 
@@ -163,9 +163,9 @@ pub fn set_cfg(cfg: &Cfg) {
 }
 
 #[track_caller]
-pub fn eval(code: &str) {
+pub fn eval(code: &str) -> Result<(), LuaError> {
     let l = lua_state();
-    l.exec(code).unwrap()
+    l.exec(code)
 }
 
 // fn net_box_repeat_call_until_succeed<Args, Res, Addr>(
diff --git a/src/traft/error.rs b/src/traft/error.rs
index 80305c59c0b8baa374387f17cfbb754eb1e56dac..1d6a686a63e536a96afdb8515446d05c6a72fd51 100644
--- a/src/traft/error.rs
+++ b/src/traft/error.rs
@@ -1,4 +1,5 @@
 use crate::traft::RaftId;
+use ::tarantool::tlua::LuaError;
 use raft::StorageError;
 use rmp_serde::decode::Error as RmpDecodeError;
 use thiserror::Error;
@@ -21,6 +22,8 @@ pub enum Error {
         instance_cluster_id: String,
         cluster_cluster_id: String,
     },
+    #[error("error during execution of lua code: {0}")]
+    Lua(#[from] LuaError),
 }
 
 #[derive(Debug, Error)]
diff --git a/src/traft/mod.rs b/src/traft/mod.rs
index 008234af4e6287602d686c4f2d731a183053f301..c4c961dca6a364ae899dddbb45e286bb22b9f76e 100644
--- a/src/traft/mod.rs
+++ b/src/traft/mod.rs
@@ -12,6 +12,7 @@ pub mod topology;
 use crate::stringify_debug;
 use crate::util::Uppercase;
 use ::raft::prelude as raft;
+use ::tarantool::tlua::LuaError;
 use ::tarantool::tuple::AsTuple;
 use serde::de::DeserializeOwned;
 use serde::{Deserialize, Serialize};
@@ -77,9 +78,7 @@ pub enum Op {
         msg: String,
     },
     /// Evaluate the code on every instance in cluster.
-    EvalLua {
-        code: String,
-    },
+    EvalLua(OpEvalLua),
     ///
     ReturnOne(OpReturnOne),
     PersistPeer {
@@ -97,7 +96,7 @@ impl std::fmt::Display for Op {
         match self {
             Self::Nop => f.write_str("Nop"),
             Self::Info { msg } => write!(f, "Info({msg:?})"),
-            Self::EvalLua { code } => write!(f, "EvalLua({code:?})"),
+            Self::EvalLua(OpEvalLua { code }) => write!(f, "EvalLua({code:?})"),
             Self::ReturnOne(_) => write!(f, "ReturnOne"),
             Self::PersistPeer { peer } => {
                 write!(f, "PersistPeer{}", peer)
@@ -117,10 +116,7 @@ impl Op {
                 crate::tlog!(Info, "{msg}");
                 Box::new(())
             }
-            Self::EvalLua { code } => {
-                crate::tarantool::eval(code);
-                Box::new(())
-            }
+            Self::EvalLua(op) => Box::new(op.result()),
             Self::ReturnOne(op) => Box::new(op.result()),
             Self::PersistPeer { peer } => {
                 Storage::persist_peer(peer).unwrap();
@@ -155,6 +151,24 @@ impl OpResult for OpReturnOne {
     }
 }
 
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+pub struct OpEvalLua {
+    pub code: String,
+}
+
+impl OpResult for OpEvalLua {
+    type Result = Result<(), LuaError>;
+    fn result(&self) -> Self::Result {
+        crate::tarantool::eval(&self.code)
+    }
+}
+
+impl From<OpEvalLua> for Op {
+    fn from(op: OpEvalLua) -> Op {
+        Op::EvalLua(op)
+    }
+}
+
 pub trait OpResult {
     type Result: 'static;
     fn result(&self) -> Self::Result;