diff --git a/execution/execution.go b/execution/execution.go
index ed822a712d1e2d694ba5367c233f71541bf87e50..caff450fc61c4264a01a164b4dd2f21a25d2bdcf 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -150,8 +150,14 @@ func (exe *executor) Reset() error {
 
 // If the tx is invalid, an error will be returned.
 // Unlike ExecBlock(), state will not be altered.
-func (exe *executor) Execute(tx txs.Tx) error {
+func (exe *executor) Execute(tx txs.Tx) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v", tx.String(), r)
+		}
+	}()
 	logger := logging.WithScope(exe.logger, "executor.Execute(tx txs.Tx)")
+	logging.TraceMsg(logger, "Executing transaction", "tx", tx.String())
 	// TODO: do something with fees
 	fees := uint64(0)
 
diff --git a/txs/tx.go b/txs/tx.go
index 2d35e77620d8fbc043fd09dba182e37afe85e74f..c24018d44e02d716854810bd155b13af73a81f71 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -101,6 +101,7 @@ type (
 	// TODO: replace with sum-type struct like ResultEvent
 	Tx interface {
 		WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
+		String() string
 	}
 
 	Wrapper struct {