diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42a591bd..21a3f4b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
 
 - BREAKING: Use new native `bigint` type. This requires ReScript compiler version "11.1.0-rc.6" or higher. https://github.com/rescript-association/rescript-core/pull/207
 - `Int`, `Float`, `BigInt`: use optional args and deprecate `xxxWithRadix`, `xxxWithPrecision` etc. https://github.com/rescript-association/rescript-core/pull/209
+- BREAKING: Add optional `~message: string=?` to `Option.getExn`. This also changes the error raised by `Option.getExn` from `Not_found` to a regular JS error. https://github.com/rescript-association/rescript-core/pull/212
 
 ## 1.2.0
 
diff --git a/src/Core__Option.mjs b/src/Core__Option.mjs
index 776bc0bf..f0a8e401 100644
--- a/src/Core__Option.mjs
+++ b/src/Core__Option.mjs
@@ -1,6 +1,7 @@
 // Generated by ReScript, PLEASE EDIT WITH CARE
 
 import * as Caml_option from "rescript/lib/es6/caml_option.js";
+import * as Core__Error from "./Core__Error.mjs";
 
 function filter(opt, p) {
   if (opt !== undefined && p(Caml_option.valFromOption(opt))) {
@@ -16,14 +17,12 @@ function forEach(opt, f) {
   
 }
 
-function getExn(x) {
+function getExn(x, message) {
   if (x !== undefined) {
     return Caml_option.valFromOption(x);
+  } else {
+    return Core__Error.panic(message !== undefined ? message : "Option.getExn called for None value");
   }
-  throw {
-        RE_EXN_ID: "Not_found",
-        Error: new Error()
-      };
 }
 
 function mapOr(opt, $$default, f) {
diff --git a/src/Core__Option.res b/src/Core__Option.res
index a799a0ea..ed55f10b 100644
--- a/src/Core__Option.res
+++ b/src/Core__Option.res
@@ -34,10 +34,16 @@ let forEach = (opt, f) =>
   | None => ()
   }
 
-let getExn = x =>
+let getExn = (x, ~message=?) =>
   switch x {
   | Some(x) => x
-  | None => raise(Not_found)
+  | None =>
+    Core__Error.panic(
+      switch message {
+      | None => "Option.getExn called for None value"
+      | Some(message) => message
+      },
+    )
   }
 
 external getUnsafe: option<'a> => 'a = "%identity"
diff --git a/src/Core__Option.resi b/src/Core__Option.resi
index fbaceba4..6f920896 100644
--- a/src/Core__Option.resi
+++ b/src/Core__Option.resi
@@ -66,18 +66,19 @@ Option.forEach(None, x => Console.log(x)) // returns ()
 let forEach: (option<'a>, 'a => unit) => unit
 
 /**
-`getExn(opt)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception.
+`getExn(opt, ~message=?)` returns `value` if `opt` is `Some(value)`, otherwise raises an exception with the message provided, or a generic message if no message was provided.
 
 ```rescript
 Option.getExn(Some(3)) // 3
 Option.getExn(None) /* Raises an Error */
+Option.getExn(None, ~message="was None!") /* Raises an Error with the message "was None!" */
 ```
 
 ## Exceptions
 
 - Raises an error if `opt` is `None`
 */
-let getExn: option<'a> => 'a
+let getExn: (option<'a>, ~message: string=?) => 'a
 
 /**
 `getUnsafe(opt)` returns `value` if `opt` is `Some(value)`, otherwise `undefined`.
diff --git a/test/Test.mjs b/test/Test.mjs
index 1fe28b2a..1824f710 100644
--- a/test/Test.mjs
+++ b/test/Test.mjs
@@ -13,7 +13,7 @@ function print(value) {
   if (match === "object" || match === "bigint") {
     return Util.inspect(value);
   } else if (match === "string") {
-    return Core__Option.getExn(JSON.stringify(value));
+    return Core__Option.getExn(JSON.stringify(value), undefined);
   } else {
     return String(value);
   }
diff --git a/test/TypedArrayTests.mjs b/test/TypedArrayTests.mjs
index f18efc85..95a7391c 100644
--- a/test/TypedArrayTests.mjs
+++ b/test/TypedArrayTests.mjs
@@ -56,31 +56,31 @@ assertTrue("fromArray", (function () {
         return areSame(Core__Option.getExn(new BigInt64Array([
                               num1,
                               num2
-                            ])[1]), num2);
+                            ])[1], undefined), num2);
       }));
 
 assertTrue("fromBuffer", (function () {
         var x = new BigInt64Array(new ArrayBuffer(16));
         x[1] = num2;
-        return areSame(Core__Option.getExn(x[1]), num2);
+        return areSame(Core__Option.getExn(x[1], undefined), num2);
       }));
 
 assertWillThrow("fromBuffer when too short can throw when used", (function () {
         var x = new BigInt64Array(new ArrayBuffer(1));
         x[0] = num1;
-        areSame(Core__Option.getExn(x[0]), num1);
+        areSame(Core__Option.getExn(x[0], undefined), num1);
       }));
 
 assertTrue("fromBufferWithRange", (function () {
         var x = new BigInt64Array(new ArrayBuffer(16), 0, 1);
         x[0] = num1;
-        return areSame(Core__Option.getExn(x[0]), num1);
+        return areSame(Core__Option.getExn(x[0], undefined), num1);
       }));
 
 assertWillThrow("fromBufferWithRange is unsafe, out of range", (function () {
         var x = new BigInt64Array(new ArrayBuffer(16), 13, 1);
         x[0] = num1;
-        areSame(Core__Option.getExn(x[0]), num1);
+        areSame(Core__Option.getExn(x[0], undefined), num1);
       }));
 
 assertTrue("fromLength is NOT in bytes", (function () {