title: SQL Server error - Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements
body: <p>I write this stored procedure</p>
  
  <pre><code>ALTER PROCEDURE [dbo].[CERRARVIAJE] 
  (   @ViajeID INT, 
      @Reloj MONEY, 
      @Peaje MONEY, 
      @Equipaje MONEY, 
      @Adicional MONEY, 
      @Plus MONEY, 
      @MontoAutorizado MONEY, 
      @CerrarEnBase BIT, 
      @UsuarioCierra INT, 
      @Motivo Varchar(100), 
      @Fecha DATETIME
  )
  AS
  BEGIN 
      SET NOCOUNT ON;
      SET XACT_ABORT ON
  
      DECLARE @NuevoEstado INT
      DECLARE @DireccionDestino VARCHAR(200)
      DECLARE @Punto Geography
      DECLARE @movil INT
      DECLARE @chofer INT
      DECLARE @Cierre VARCHAR(10)
      DECLARE @VisualId VARCHAR(10)
  
      IF @Fecha IS NULL
      BEGIN
          SET @Fecha = GETDATE()
      END
  
      IF @ViajeID IS NOT NULL
      BEGIN
          SELECT  @movil = C.MovilID, 
                  @chofer = V.ChoferID , 
                  @VisualId = V.VisualID, 
                  @DireccionDestino = DireccionDestino, 
                  @Punto = Destino 
          FROM CHOFERES C (NOLOCK)
          INNER JOIN VIAJES V (NOLOCK)
              ON C.Id = V.ChoferId  
          WHERE V.ID = @ViajeID
  
          --Si el usuario que cierra es el chofer, se obtiene su id de usuario
          IF @UsuarioCierra = -1
          BEGIN
              SELECT @UsuarioCierra = Ch.UsuarioID From Viajes V (NOLOCK), Choferes Ch (NOLOCK) Where V.ID = @ViajeID AND Ch.ID = V.ChoferID
          END
  
          --Se establece el nuevo estado que tendrá el viaje
          IF @CerrarEnBase = 0 
          BEGIN
              SET @NuevoEstado  = 13 --Completado
          END
          ELSE
          BEGIN
              SET @NuevoEstado  = 18 --Cierra Base
          END
  
          --El motivo sólo es necesario si el viaje lo cerró la base
          IF @CerrarEnBase = 0
          BEGIN
              SET @Motivo = ''
          END
  
          --Si el operador no puso dirección de destino al crear el viaje se busca mediante la tabla Recorridos
          IF @DireccionDestino IS NULL
          BEGIN
              SELECT  @DireccionDestino = Direccion, 
                      @Punto = Punto 
              FROM Recorridos (NOLOCK) 
              WHERE   ViajeID = @ViajeID 
                      AND ID IN   (SELECT MAX(ID) MID 
                                  FROM Recorridos (NOLOCK) 
                                  WHERE ViajeID = @ViajeID)
          END
  
          DECLARE @Success    BIT
          SELECT @Success = 0
          WHILE @Success = 0
  
          BEGIN TRY
              IF @@TRANCOUNT &gt; 0
              BEGIN
                  SAVE TRANSACTION CERRARVIAJE
              END
              ELSE
              BEGIN
                  BEGIN TRANSACTION
              END
  
              --se actualizan los datos del viaje que se va a cerrar       
              UPDATE  Viajes 
              SET     EstadoID = @NuevoEstado, 
                      FechaCompletado = @Fecha, 
                      CerroUsuarioID = @UsuarioCierra, 
                      MotivoCerrarBase = @Motivo, 
                      Destino = @Punto, 
                      DireccionDestino = @DireccionDestino
              WHERE ID = @ViajeID
  
              --se cambia el estado del móvil en calle
              UPDATE MOVILESENCALLE SET ESTADO = 1 WHERE ID = @movil
  
              --se guarda el registro en ViajesLog
              INSERT INTO [dbo].[ViajesLog]
                          ([Id],[TipoViajeId],[EstadoId],[UsuarioId],[ChoferId],[SubEmpresaId],[PINPasajero],[FechaSolicitado],[FechaUltimoEstado],[FechaAceptado],[FechaPasajeroABordo],[FechaCompletado]
                          ,[FechaCancelado],[FechaCanceladoPasajero],[Origen],[DireccionOrigen],[Destino],[DireccionDestino],[UbicacionActual],[DireccionUbicacionActual],[FlotaIDOriginal],[FechaUniverso]
                          ,[VISUALID],[FechaCreacion],[Observaciones],[Observaciones2],[NoFumador],[AnimalDom],[ServicioVan],[Ticketera],[BaulVacio],[AireAcondicionado],[MotivoCancelacionPasajero],[NumeroViajeCliente]
                          ,[NumeroSiniestro],[TipoMovilId],[CerroUsuarioId],[TienePremio],[Premio],[RequiereVoucher],[MotivoCerrarBase],[EsMensajeria],[FechaObjetivo],[Autorizacion]
                          ,[NombreApellidoPasajero],[CelularPasajero],[ZonaID],[OperadorID],[AutorizacionUsuarioId],[Condicional], [MovilId])
              SELECT V.[Id],[TipoViajeId],[EstadoId],V.[UsuarioId],[ChoferId],[SubEmpresaId],[PINPasajero],[FechaSolicitado],[FechaUltimoEstado],[FechaAceptado],[FechaPasajeroABordo],[FechaCompletado]
                      ,[FechaCancelado],[FechaCanceladoPasajero],[Origen],[DireccionOrigen],[Destino],[DireccionDestino],[UbicacionActual],[DireccionUbicacionActual],[FlotaIDOriginal],[FechaUniverso]
                      ,[VISUALID],[FechaCreacion],V.[Observaciones],[Observaciones2],[NoFumador],[AnimalDom],[ServicioVan],[Ticketera],[BaulVacio],[AireAcondicionado],[MotivoCancelacionPasajero],[NumeroViajeCliente]
                      ,[NumeroSiniestro],[TipoMovilId],[CerroUsuarioId],[TienePremio],[Premio],[RequiereVoucher],[MotivoCerrarBase],[EsMensajeria],[FechaObjetivo],[Autorizacion]
                      ,[NombreApellidoPasajero],[CelularPasajero],[ZonaID],[OperadorID],[AutorizacionUsuarioId],[Condicional], C.MovilId
              FROM [dbo].[Viajes] V (NOLOCK) 
              LEFT JOIN Choferes C (NOLOCK)
                  ON V.ChoferId = C.Id
              WHERE V.ID = @ViajeID 
  
              --se elimina el registro de la tabla Viajes
              DELETE FROM Viajes 
              WHERE ID = @ViajeID
  
              --se elimina el registro de la tabla MontosViajes
              DELETE FROM [dbo].[MontosViajes] WHERE 
              ViajeID = @ViajeID
  
              --se crea el nuevo registro en la tabla MontosViajes
              INSERT INTO [dbo].[MontosViajes] ([ViajeId],[Reloj],[Peaje],[Equipaje],[Adicional],[Plus],[MontoTotal],
                      [MontoNetoChofer],[MontoTaxiCorp],[MontoFlotaRecibioViaje],[MontoFlotaRealizoViaje],
                      [FlotaRecibioViajeID],[FlotaRealizoViajeID],[SubEmpresaID])
              SELECT TOP 1    @ViajeID, 
                              @Reloj, 
                              @Peaje, 
                              @Equipaje, 
                              @Adicional, 
                              @Plus, 
                              @MontoAutorizado,
                              @MontoAutorizado * (1 - F.DescuentoPorcentaje / 100.0) - F.DescuentoFijoTotal,  
                              0, 
                              CASE WHEN V.FlotaIdOriginal = SF.FlotaID THEN F.DescuentoFijoTotal 
                                  ELSE F.DescuentoFijoPropio 
                              END + @MontoAutorizado * (F.DescuentoPorcentaje / 100.0),
                              CASE WHEN V.FlotaIdOriginal = SF.FlotaID THEN 0 
                                  ELSE F.DescuentoFijoOtraFlota 
                              END,
                              V.FlotaIdOriginal, 
                              SF.FlotaID, 
                              V.SubEmpresaID
              FROM    ViajesFull V (NOLOCK) 
              INNER JOIN Choferes C (NOLOCK)
                  ON V.ChoferId = C.Id
              INNER JOIN Moviles M (NOLOCK)
                  ON C.MovilId = M.Id  
              INNER JOIN SubFlotas SF (NOLOCK)
                  ON M.SubFlotaID = SF.ID
              INNER JOIN FLotas F (NOLOCK)
                  ON V.FlotaIdOriginal = F.ID
              WHERE V.ID = @ViajeID 
  
              --se establece texto para guardar en el log
              IF @CerrarEnBase = 0
              BEGIN
                  SET @Cierre = 'FINAL '
              END     
              ELSE
              BEGIN
                  SET @Cierre = 'A BASE '
              END
  
              --se guarda registro en el log de acciones
              INSERT INTO AccionesLog (ChoferID, MovilID, ViajeID, UsuarioID, Accion, Stamp)
              VALUES (@chofer, @movil, @ViajeID, @UsuarioCierra, 'CERRO VIAJE ' + @Cierre + @VisualId + ' POR ' + CONVERT(VARCHAR, @MontoAutorizado), GETDATE())
          lbexit:
                  IF @@TRANCOUNT = 0
                      COMMIT TRAN;
  
                  SET @Success = 1 -- To exit the loop
              END TRY                     
  
              BEGIN CATCH
  
                  DECLARE @ERROR INT, @MESSAGE VARCHAR(4000), @XSTATE INT;
                  SELECT @ERROR = ERROR_NUMBER(), @MESSAGE = ERROR_MESSAGE(), @XSTATE = XACT_STATE();
  
                  --IF @XSTATE = -1
                  --  ROLLBACK;
                  IF --@XSTATE = 1 AND 
                  @@TRANCOUNT = 0
                      ROLLBACK;
                  IF --@XSTATE = 1 AND 
                  @@TRANCOUNT &gt; 0
                      ROLLBACK TRANSACTION CERRARVIAJE;
  
  
                  IF @ERROR IN (1204, -- SqlOutOfLocks
                                  1205, -- SqlDeadlockVictim
                                  1222 -- SqlLockRequestTimeout
                                  )
                      BEGIN
                          -- This delay is to give the blocking 
                          -- transaction time to finish.
                          -- So you need to tune according to your 
                          -- environment
                          WAITFOR DELAY '00:00:02'  
                      END 
                  ELSE    
                      -- If we don't have a handler for current error
                      -- then we throw an exception and abort the loop
                      THROW;
              END CATCH
      END
  END
  </code></pre>
  
  <p>And I am having this error:  </p>
  
  <blockquote>
    <p>Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.</p>
  </blockquote>