duckdb: nodeJS: Executing a bad query can terminate the node process

What happens?

Executing a bad query (e.g db.all("SELECT CAST('11:10:10' AS BLAH) as time", ...)) using the nodejs binding can terminate the process calling it. This means that in a server environment, the client code has no chance to recover by using a try/catch block around the query execution.

To Reproduce

Steps to reproduce

  1. Create a simple node.js project with the following package.json and index.js under a common directory (for convenience you can find also find the project contents here https://replit.com/@ud3sh/duckdb-query-failure-can-cause-process-to-end-fixed#index.js).
--- package.json ---
{
  "name": "dummy-duckdb-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "duckdb": "next"
  },
  "author": ""
}

--- index.js ---
const duckdb = require('duckdb')
const db = new duckdb.Database(":memory:");

console.log('Program Started ...');
try {
  db.all("SELECT CAST('11:10:10' AS BAD_TYPE) as time", function(err, res) {
    if (err) {
      console.log(`Encountered error ${err}`);
      throw err;
    } else {
      console.log(`We got results : ${res[0]}`);
    }
  });
} catch (error) {
  console.log(`Caught Error: ${error}`);
}
console.log('Program exited cleanly!');
  1. Open a command prompt, navigate to the project directory, and run npm install && node index.js

Expected Result

An exception gets thrown by the duckdb node library, this is caught in the client code by the try/catch block, and Program exited cleanly! would be printed out.

Actual Result

The process terminates prematurely. The catch block doesn’t get executed. If you are in a unix environment, running echo $? after running node index.js yields a non zero exit code.

An error message Did you mean "datetime"?] { errno: -1, code: 'DUCKDB_NODEJS_ERROR'} is printed out from the library. However, this doesn’t help the calling code as the process terminates after printing out the message.

Additional Notes

Previously, this was an issue with syntactically correct queries that didn’t have explicit type support in Node.js as well. For instance, SELECT CAST('11:10:10' AS TIME) as time. However this PR from @jwills seemed to have fixed that particular case https://github.com/duckdb/duckdb/pull/5130 in v@next (still an issue on 0.5.1)

OS:

OSX

DuckDB Version:

0.5.1, 0.5.2-dev1445.0

DuckDB Client:

Node.js

Full Name:

Udesh

Affiliation:

Evidence (https://evidence.dev/)

Have you tried this on the latest master branch?

  • I agree

Have you tried the steps to reproduce? Do they include all relevant data and configuration? Does the issue you report still appear there?

  • I agree

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 17 (10 by maintainers)

Most upvoted comments

I got the same error as @Mause; @ud3sh is it possible you’re running this on an M1 Mac? I’m on an old (Intel) MBP.

I don’t have access to any Apple hardware sorry, I have a Xubuntu 22.04.1 x86_64 system. If this is only occurring on M1 hardware someone else will have to look into it

@archiewood not quite, something closer to this:

var duckdb = require('duckdb');

const runQuery = db => {
    db.all('SELECT 42 AS fortytwo', function (err, res) {
        if (err) {
            throw err;
        }
        console.log(res[0].fortytwo)
    });
};

let promise = new Promise(function (resolve, reject) {
    const db = new duckdb.Database(':memory:', (err) => err ? reject(err) : resolve(db));
});

promise
    .then(db => {
        runQuery(db);
    })
    .catch(err => {
        console.log(err);
    });

and we are aware that this API is very awkward to consume, we’re doing some work at the present to rework it

Replicating the above

Just tried both the above test cases (1. from @ud3sh and 2. from @Mause )with 0.5.2-dev2131.0.

Neither processes die on me, but both report the same error as @ud3sh was getting.

> node start.js

Program Started ...
Caught Error: Error: Connection created on database that was not yet initialized
Program exited cleanly!
exited

I also tried changing an in memory db for a local duckdb file which was also the same.


Trying the docs

I then just copied the example straight from the node.js docs:

var duckdb = require('duckdb');
var db = new duckdb.Database(':memory:');

db.all('SELECT 42 AS fortytwo', function(err, res) {
    if (err) {
      throw err;
    }
    console.log(res[0].fortytwo)
  });

Which throws the same error as above: Connection created on database that was not yet initialized

or an even more minimal example:

var duckdb = require('duckdb');
var db = new duckdb.Database(':memory:');
var con = db.connect();

Will boot up my windows machine to see if I can replicate there also

Okay then, so at a guess, it’s something to do with the copies of DuckDB you’re compiling on your machines (either due to something installed on the machines themselves, or due to the hardware somehow?), due to the (current) lack of binaries. This is somewhat supported by the fact that I’m unable to replicate this on the Github Actions MacOS machines, which are also x86_64

See https://github.com/Mause/dummy-duckdb-project-5161/actions/runs/3386934345/jobs/5626992593

@hannes / @mytherin, thoughts?

I’m on an older Mac and am not experiencing the issue where a crash happens on an invalid type

Hi, thanks for raising this issue! Unfortunately, I’m unable to replicate it on either 0.5.1 or 0.5.2-dev1445.0.

Your test case did have a race condition bug in it though, perhaps that’s what was causing it for you?

This is the fixed code I tested with:

const duckdb = require('duckdb')
const db = new duckdb.Database(":memory:");

async function main() {
    console.log('Program Started ...');
    try {
        const res = await new Promise((resolve, reject) =>
            db.all("SELECT CAST('11:10:10' AS BAD_TYPE) as time", (err, res) => err ? reject(err) : resolve(res))
        );
        console.log(`We got results : ${res[0]}`);
    } catch (error) {
        console.log(`Caught Error: ${error}`);
    }
    console.log('Program exited cleanly!');
}

main().then(r => console.log('exited'));

which gives the following, which seems correct

$ node index.js
Program Started ...
Caught Error: Error: Catalog Error: Type with name BAD_TYPE does not exist!
Did you mean "datetime"?
Program exited cleanly!
exited

Process finished with exit code 0

Can you confirm if this is still an issue for you with the revised test case?