diff --git a/include/fmpi_mpi.h b/include/fmpi_mpi.h
deleted file mode 100644
index 90ede0ef77c6a490e39ebde4d4b580075cd42a75..0000000000000000000000000000000000000000
--- a/include/fmpi_mpi.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: 0BSD
-/*!
- * @file
- * @license{
- * BSD Zero Clause License
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- * }
- */
-/*==============================================================================
-    GUARD
-==============================================================================*/
-#ifndef FMPI_MPI_H_20211219234201
-#define FMPI_MPI_H_20211219234201
-/*==============================================================================
-    INCLUDE
-==============================================================================*/
-// C Standard Library
-// External
-#include <mpi.h> // MPI_MAX_PROCESSOR_NAME
-// Internal
-/*==============================================================================
-    STRUCT
-==============================================================================*/
-struct fmpi_mpi_ctx {
-    int rank;
-    int size;
-    char cpu_name[MPI_MAX_PROCESSOR_NAME];
-    int cpu_name_length;
-    int root;
-    int futhark_err_class;
-    int futhark_err_code;
-};
-struct fmpi_ctx;
-/*==============================================================================
-    PUBLIC FUNCTION
-==============================================================================*/
-struct fmpi_mpi_ctx * fmpi_mpi_init(int * argc, char ** argv[]);
-void fmpi_mpi_exit(struct fmpi_mpi_ctx * ctx);
-void fmpi_mpi_abort(struct fmpi_mpi_ctx * ctx);
-_Bool fmpi_mpi_is_root(const struct fmpi_mpi_ctx * const ctx);
-_Bool fmpi_mpi_has_error(struct fmpi_mpi_ctx * const ctx, int err_id, const char * const func_name);
-_Bool fmpi_mpi_is_initialized(struct fmpi_mpi_ctx * const ctx);
-_Bool fmpi_mpi_is_finalized(struct fmpi_mpi_ctx * const ctx);
-struct fmpi_mpi_ctx * fmpi_mpi_create(int root);
-void fmpi_mpi_destroy(struct fmpi_mpi_ctx ** const ctx);
-void fmpi_mpi_ctx_print(const struct fmpi_mpi_ctx * const ctx);
-/*==============================================================================
-    GUARD
-==============================================================================*/
-#endif // FMPI_MPI_H_20211219234201
diff --git a/include/internal/fmpi_mpi.h b/include/internal/fmpi_mpi.h
new file mode 100644
index 0000000000000000000000000000000000000000..cfb97a4a484f25e8a183ec066cf2fe90a4148a63
--- /dev/null
+++ b/include/internal/fmpi_mpi.h
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: 0BSD
+/*!
+ * @file
+ * @license{
+ * BSD Zero Clause License
+ *
+ * Copyright (c) 2022 by Raphael Bach
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ * }
+ */
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#ifndef FMPI_MPI_H_20211219234201
+#define FMPI_MPI_H_20211219234201
+/*==============================================================================
+    INCLUDE
+==============================================================================*/
+// C Standard Library
+// External
+#include <mpi.h> // MPI_MAX_PROCESSOR_NAME
+// Internal
+#include "fmpi_error.h"
+/*==============================================================================
+    STRUCT
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_mpi_ctx
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+typedef struct fmpi_mpi_ctx {
+    int rank; //!< TODO
+    int size; //!< TODO
+    char cpu_name[MPI_MAX_PROCESSOR_NAME]; //!< TODO
+    int cpu_name_length; //!< TODO
+    int root; //!< TODO
+    int futhark_err_class; //!< TODO
+    int futhark_err_code; //!< TODO
+    const struct fmpi_error_handler * err_handler; //!< TODO
+} fmpi_mpi_ctx;
+/*==============================================================================
+    PUBLIC FUNCTION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_mpi_init()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] argc : TODO
+ * @param[in] argv : TODO
+ * @param[in] err_handler : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+struct fmpi_mpi_ctx * fmpi_mpi_init(
+    int * argc, char ** argv[], const struct fmpi_error_handler * err_handler
+);
+/*------------------------------------------------------------------------------
+    fmpi_mpi_exit()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+int fmpi_mpi_exit(struct fmpi_mpi_ctx ** ctx);
+/*------------------------------------------------------------------------------
+    fmpi_mpi_is_root()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+_Bool fmpi_mpi_is_root(const struct fmpi_mpi_ctx * const ctx);
+/*------------------------------------------------------------------------------
+    fmpi_mpi_check_error()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ * @param[in] err_id : TODO
+ * @param[in] func : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+_Bool fmpi_mpi_check_error(
+    const struct fmpi_mpi_ctx * ctx, int err_id, const char * func
+);
+/*------------------------------------------------------------------------------
+    fmpi_mpi_ctx_print()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+void fmpi_mpi_ctx_print(const struct fmpi_mpi_ctx * ctx);
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#endif // FMPI_MPI_H_20211219234201
diff --git a/src/fmpi_mpi.c b/src/fmpi_mpi.c
index cc78b479be9f67ae9b2d6cd5a839b322e34aba3e..9ba26be0ee9dcd84af149a9a6a45e1956b5b9807 100644
--- a/src/fmpi_mpi.c
+++ b/src/fmpi_mpi.c
@@ -4,6 +4,8 @@
  * @license{
  * BSD Zero Clause License
  *
+ * Copyright (c) 2022 by Raphael Bach
+ *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted.
  *
@@ -20,89 +22,81 @@
     INCLUDE
 ==============================================================================*/
 // Own header
-#include "fmpi_mpi.h"
+#include "internal/fmpi_mpi.h"
 // C Standard Library
 #include <assert.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 // External
 #include <mpi.h>
 // Internal
-#include "fmpi_ctx.h"
+#include "internal/fmpi_error.h"
 /*==============================================================================
     DEFINE
 ==============================================================================*/
-#define FMPI_MPI_RANK_ROOT_DEFAULT 0
+#define FMPI_MPI_ROOT 0
+/*==============================================================================
+    MACRO
+==============================================================================*/
+#define FMPI_RAISE_MPI_ERROR(ctx, ...) \
+do { \
+    if((ctx)->err_handler != NULL) { \
+        FMPI_RAISE_ERROR((ctx)->err_handler, "MPI", __VA_ARGS__); \
+    } \
+} while(0)
 /*==============================================================================
     PUBLIC FUNCTION
 ==============================================================================*/
 /*------------------------------------------------------------------------------
     fmpi_mpi_init()
 ------------------------------------------------------------------------------*/
-struct fmpi_mpi_ctx * fmpi_mpi_init(int * argc, char ** argv[])
-{
-    struct fmpi_mpi_ctx * ctx = fmpi_mpi_create(FMPI_MPI_RANK_ROOT_DEFAULT);
+struct fmpi_mpi_ctx * fmpi_mpi_init(
+    int * const argc, char *** const argv,
+    const struct fmpi_error_handler * const err_handler
+){
+    struct fmpi_mpi_ctx * ctx = malloc(sizeof(*ctx));
     if(ctx == NULL) {
-        fprintf(stderr, "fmpi_mpi_create() failed!\n");
+        if(err_handler != NULL) {
+            FMPI_RAISE_ERROR(err_handler, "MPI", "malloc(fmpi_mpi_ctx) failed!");
+        }
         return NULL;
     }
+    ctx->root = FMPI_MPI_ROOT;
+    ctx->err_handler = (err_handler != NULL) ? err_handler : NULL;
 
     int err_id = MPI_Init(argc, argv);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Init()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
+    if(fmpi_mpi_check_error(ctx, err_id, "MPI_Init") == true) {
+        return ctx;
     }
+
     err_id = MPI_Comm_rank(MPI_COMM_WORLD, &ctx->rank);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Comm_rank()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
+    fmpi_mpi_check_error(ctx, err_id, "MPI_Comm_rank");
+
     err_id = MPI_Comm_size(MPI_COMM_WORLD, &ctx->size);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Comm_size()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
-    // `size` is used with `malloc()` and `malloc(0)` is implementation-defined.
+    fmpi_mpi_check_error(ctx, err_id, "MPI_Comm_size");
+    // `ctx->size` is used with `malloc()` and `malloc(0)` is implementation-defined.
     assert(ctx->size > 0);
+
     err_id = MPI_Get_processor_name(ctx->cpu_name, &ctx->cpu_name_length);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Get_processor_name()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
-    err_id = MPI_Add_error_class(&ctx->futhark_err_class);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Get_processor_name()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
-    err_id = MPI_Add_error_code(ctx->futhark_err_class, &ctx->futhark_err_code);
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Get_processor_name()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
-    err_id = MPI_Add_error_string(ctx->futhark_err_code, "");
-    if(fmpi_mpi_has_error(ctx, err_id, "MPI_Get_processor_name()")) {
-        fmpi_mpi_destroy(&ctx); return NULL;
-    }
+    fmpi_mpi_check_error(ctx, err_id, "MPI_Get_processor_name");
+
     return ctx;
 }
 /*------------------------------------------------------------------------------
     fmpi_mpi_exit()
 ------------------------------------------------------------------------------*/
-void fmpi_mpi_exit(struct fmpi_mpi_ctx * ctx)
+int fmpi_mpi_exit(struct fmpi_mpi_ctx ** const ctx)
 {
-    if(ctx != NULL) {
-        fmpi_mpi_destroy(&ctx);
-    }
-    if(fmpi_mpi_is_initialized(ctx) && !fmpi_mpi_is_finalized(ctx)) {
-        const int err_id = MPI_Finalize();
-        fmpi_mpi_has_error(ctx, err_id, "MPI_Finalize()");
-    }
-}
-/*------------------------------------------------------------------------------
-    fmpi_mpi_abort()
-------------------------------------------------------------------------------*/
-void fmpi_mpi_abort(struct fmpi_mpi_ctx * ctx)
-{
-    if(ctx != NULL) {
-        fmpi_mpi_destroy(&ctx);
-    }
-    if(fmpi_mpi_is_initialized(ctx) && !fmpi_mpi_is_finalized(ctx)) {
-        MPI_Abort(MPI_COMM_WORLD, MPI_ERR_UNKNOWN);
+    assert(ctx != NULL);
+    assert(*ctx != NULL);
+
+    int err_id = MPI_Finalize();
+    if(fmpi_mpi_check_error(*ctx, err_id, "MPI_Finalize") == true) {
+        err_id = -1;
     }
+    free(*ctx); *ctx = NULL;
+    return err_id;
 }
 /*------------------------------------------------------------------------------
     fmpi_mpi_is_root()
@@ -113,70 +107,24 @@ _Bool fmpi_mpi_is_root(const struct fmpi_mpi_ctx * const ctx)
     return ctx->rank == ctx->root;
 }
 /*------------------------------------------------------------------------------
-    fmpi_mpi_has_error()
+    fmpi_mpi_check_error()
 ------------------------------------------------------------------------------*/
-_Bool fmpi_mpi_has_error(struct fmpi_mpi_ctx * const ctx, int err_id, const char * const func_name)
-{
-    int rank = -1;
-    if(ctx != NULL) {
-        rank = ctx->rank;
-    }
+_Bool fmpi_mpi_check_error(
+    const struct fmpi_mpi_ctx * ctx, int err_id, const char * const func
+){
+    assert(ctx != NULL);
+    assert(func != NULL);
     if(err_id != MPI_SUCCESS) {
-        char err_array[MPI_MAX_ERROR_STRING] = {0};
+        char err_str[MPI_MAX_ERROR_STRING] = {'\0'};
         int err_str_len = 0;
-        const int err_str_id = MPI_Error_string(err_id, err_array, &err_str_len);
-        if(err_str_id != MPI_SUCCESS) {
-            fprintf(stderr, "[MPI ERROR rank=%d] MPI_Error_string() failed!\n", rank);
+        err_id = MPI_Error_string(err_id, err_str, &err_str_len);
+        if(err_id != MPI_SUCCESS) {
+            FMPI_RAISE_MPI_ERROR(ctx, "MPI_Error_string() failed!");
         }
-        const char * err_str = err_str_id == MPI_SUCCESS ? err_array : "";
-        fprintf(stderr, "[MPI ERROR rank=%d] %s failed!: %s\n", rank, func_name, err_str);
-        return 1;
+        FMPI_RAISE_MPI_ERROR(ctx, "%s() failed! %s", func, err_str);
+        return true;
     }
-    return 0;
-}
-/*------------------------------------------------------------------------------
-    fmpi_mpi_is_initialized()
-------------------------------------------------------------------------------*/
-_Bool fmpi_mpi_is_initialized(struct fmpi_mpi_ctx * const ctx)
-{
-    int is_initialized = 0;
-    const int err_id = MPI_Initialized(&is_initialized);
-    fmpi_mpi_has_error(ctx, err_id, "MPI_Initialized()");
-    return is_initialized;
-}
-/*------------------------------------------------------------------------------
-    fmpi_mpi_is_finalized()
-------------------------------------------------------------------------------*/
-_Bool fmpi_mpi_is_finalized(struct fmpi_mpi_ctx * const ctx)
-{
-    int is_finalized = 0;
-    const int err_id = MPI_Finalized(&is_finalized);
-    fmpi_mpi_has_error(ctx, err_id, "MPI_Finalized()");
-    return is_finalized;
-}
-/*------------------------------------------------------------------------------
-    fmpi_mpi_create()
-------------------------------------------------------------------------------*/
-struct fmpi_mpi_ctx * fmpi_mpi_create(int root)
-{
-    struct fmpi_mpi_ctx * ctx = malloc(sizeof(*ctx));
-    if(ctx == NULL) {
-        fprintf(stderr, "malloc(fmpi_mpi_ctx) failed!\n");
-        return NULL;
-    }
-    ctx->root = root;
-    return ctx;
-}
-/*------------------------------------------------------------------------------
-    fmpi_mpi_destroy()
-------------------------------------------------------------------------------*/
-void fmpi_mpi_destroy(struct fmpi_mpi_ctx ** const ctx)
-{
-    assert(ctx != NULL);
-    assert(*ctx != NULL);
-
-    free((*ctx));
-    (*ctx) = NULL;
+    return false;
 }
 /*------------------------------------------------------------------------------
     fmpi_mpi_ctx_print()
@@ -184,7 +132,6 @@ void fmpi_mpi_destroy(struct fmpi_mpi_ctx ** const ctx)
 void fmpi_mpi_ctx_print(const struct fmpi_mpi_ctx * const ctx)
 {
     assert(ctx != NULL);
-
     printf("MPI size: %d\n", ctx->size);
     printf("MPI rank: %d\n", ctx->rank);
     printf("MPI CPU name: %s\n", ctx->cpu_name);