Consegui resolver o problema.
O problema não era com o código abaixo
await session.commitTransaction(); (success)
session.endSession(); (failure)
} catch (error) { (entered)
await session.abortTransaction(); (invoked)
mas foi com o loop records.forEach.
records.forEach(async (el: any) => {...});
dentro do foreach ao lançar um erro, ele não é capturado pelo bloco try catch mais externo, pois o conteúdo dentro do loop está em um contexto funcional diferente do código fora do loop.
Uma vez eu mudei o loop de
.forEach
para for (const el of records) {}
está funcionando como esperado. Postando a resposta caso alguém enfrente o mesmo no futuro. Obrigado pelo apoio pessoal :)