diff --git a/action/const.go b/action/const.go
index 4742216401..37ed32d4c6 100644
--- a/action/const.go
+++ b/action/const.go
@@ -44,6 +44,7 @@ var (
 	ErrGasTipOverFeeCap   = errors.New("tip cap is greater than fee cap")
 	ErrMissRequiredField  = errors.New("missing required field")
 	ErrValueVeryHigh      = errors.New("value is very high")
+	ErrPanicButReverted   = errors.New("panic but reverted")
 )
 
 // LoadErrorDescription loads corresponding description related to the error
diff --git a/state/factory/workingset.go b/state/factory/workingset.go
index cb28cf880a..c3d7d92d7e 100644
--- a/state/factory/workingset.go
+++ b/state/factory/workingset.go
@@ -168,7 +168,7 @@ func withActionCtx(ctx context.Context, selp *action.SealedEnvelope) (context.Co
 func (ws *workingSet) runAction(
 	ctx context.Context,
 	selp *action.SealedEnvelope,
-) (*action.Receipt, error) {
+) (receipt *action.Receipt, err error) {
 	actCtx := protocol.MustGetActionCtx(ctx)
 	if protocol.MustGetBlockCtx(ctx).GasLimit < actCtx.IntrinsicGas {
 		return nil, action.ErrGasLimit
@@ -207,6 +207,17 @@ func (ws *workingSet) runAction(
 		return nil, errors.Wrapf(err, "Failed to get hash")
 	}
 	defer ws.ResetSnapshots()
+	sn := ws.Snapshot()
+	defer func() {
+		if r := recover(); r != nil {
+			receipt = nil
+			if e := ws.Revert(sn); e != nil {
+				err = errors.Wrapf(e, "panic and recovered but failed to revert when running action: %v", r)
+				return
+			}
+			err = errors.Wrapf(action.ErrPanicButReverted, "panic and reverted when running action: %v", r)
+		}
+	}()
 	if err := ws.freshAccountConversion(ctx, &actCtx); err != nil {
 		return nil, err
 	}
@@ -736,6 +747,8 @@ func (ws *workingSet) pickAndRunActions(
 				actionIterator.PopAccount()
 				continue
 			}
+			actCtx := protocol.MustGetActionCtx(actionCtx)
+			l := log.L().With(log.Hex("actHash", actCtx.ActionHash[:]), zap.Uint64("height", ws.height))
 			receipt, err := ws.runAction(actionCtx, nextAction)
 			switch errors.Cause(err) {
 			case nil:
@@ -744,7 +757,12 @@ func (ws *workingSet) pickAndRunActions(
 				actionIterator.PopAccount()
 				continue
 			case action.ErrChainID, errUnfoldTxContainer, errDeployerNotWhitelisted:
-				log.L().Debug("runAction() failed", zap.Uint64("height", ws.height), zap.Error(err))
+				l.Debug("runAction() failed", zap.Error(err))
+				ap.DeleteAction(caller)
+				actionIterator.PopAccount()
+				continue
+			case action.ErrPanicButReverted:
+				l.Warn("runAction() panic but reverted", zap.Error(err))
 				ap.DeleteAction(caller)
 				actionIterator.PopAccount()
 				continue