From 9f74b58d66d1fcf59cdf82937dcb1d1aa546466a Mon Sep 17 00:00:00 2001
From: ybai08 <271969568+ybai08@users.noreply.github.com>
Date: Sun, 18 Oct 2026 17:45:50 -0500
Subject: [PATCH] fix: report the message of Errors thrown in user-defined
functions
When a function registered with create_function, or the step or
finalize function of an aggregate, threw an Error object, the error was
passed as-is to sqlite3_result_error, which is wrapped to take a string.
The Error was converted to an empty string, so the query failed with an
empty message, and debug builds aborted with "stringToUTF8Array expects
a string (got object)". Only thrown strings were reported correctly.
Pass the message of Error objects, and the string conversion of any
other thrown value, to sqlite3_result_error.
---
src/api.js | 12 +++++++++---
test/test_aggregate_functions.js | 19 +++++++++++++++++++
test/test_functions.js | 6 +++++-
3 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/src/api.js b/src/api.js
index 47d64ef1..e391305c 100644
--- a/src/api.js
+++ b/src/api.js
@@ -1245,6 +1245,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
sqlite3_result_null(cx);
}
};
+ var setFunctionError = function setFunctionError(cx, error) {
+ // sqlite3_result_error takes a string: passing an Error object
+ // directly would report an empty message
+ var message = error instanceof Error ? error.message : String(error);
+ sqlite3_result_error(cx, message, -1);
+ };
/** Register a custom function with SQLite
@example
Register a simple function
@@ -1266,7 +1272,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
try {
result = func.apply(null, args);
} catch (error) {
- sqlite3_result_error(cx, error, -1);
+ setFunctionError(cx, error);
return;
}
setFunctionResult(cx, result);
@@ -1367,7 +1373,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
state[p] = step.apply(null, mergedArgs);
} catch (error) {
delete state[p];
- sqlite3_result_error(cx, error, -1);
+ setFunctionError(cx, error);
}
}
@@ -1378,7 +1384,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
result = finalize(state[p]);
} catch (error) {
delete state[p];
- sqlite3_result_error(cx, error, -1);
+ setFunctionError(cx, error);
return;
}
setFunctionResult(cx, result);
diff --git a/test/test_aggregate_functions.js b/test/test_aggregate_functions.js
index d28c775f..bcbbdb9d 100644
--- a/test/test_aggregate_functions.js
+++ b/test/test_aggregate_functions.js
@@ -99,6 +99,25 @@ exports.test = function (SQL, assert) {
3,
"Aggregate functions work after an exception has been thrown in finalize"
);
+
+ db.create_aggregate("throws_error_step", {
+ step: (state, value) => { throw new Error("step error object"); },
+ });
+ assert.throws(
+ () => db.exec("SELECT throws_error_step(column1) FROM (VALUES (1));"),
+ /step error object/,
+ "Reports the message of an Error thrown in a step function"
+ );
+
+ db.create_aggregate("throws_error_finalize", {
+ step: (state, value) => value,
+ finalize: (state) => { throw new Error("finalize error object"); },
+ });
+ assert.throws(
+ () => db.exec("SELECT throws_error_finalize(column1) FROM (VALUES (1));"),
+ /finalize error object/,
+ "Reports the message of an Error thrown in a finalize function"
+ );
}
// helper function to calculate a percentile from an array. Will modify the
diff --git a/test/test_functions.js b/test/test_functions.js
index eb1cc2a8..c0b17193 100644
--- a/test/test_functions.js
+++ b/test/test_functions.js
@@ -149,7 +149,11 @@ exports.test = function(SQL, assert){
db.create_function("throwFunction", function () { throw "internal exception"; return 5;} );
assert.throws(function(){db.exec("SELECT throwFunction()");},/internal exception/, "Can handle internal exceptions");
-
+
+ db.create_function("throwErrorFunction", function () { throw new Error("internal error object"); });
+ assert.throws(function(){db.exec("SELECT throwErrorFunction()");},/internal error object/, "Reports the message of a thrown Error");
+ assert.equal(db.exec("SELECT addOne(1);")[0]["values"][0][0], 2, "Functions work after an Error has been thrown");
+
db.create_function("customeObjectFunction", function () { return {test:123};} );
assert.throws(function(){db.exec("SELECT customeObjectFunction()");},/Wrong API use/, "Reports wrong API use");