better-sqlite3 icon indicating copy to clipboard operation
better-sqlite3 copied to clipboard

Another "FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal" error

Open achou11 opened this issue 2 years ago • 5 comments

Looks like I'm running into a similar error. Apologies for potential redundancy (seem to be quite a few issues with this error message but with different causes)

Node version: 12.18.3 better-sqlite3 version: 7.5.3 OS: MacOS 11.6.7 (Big Sur), Intel

FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal.
 1: 0x1011c2ff5 node::Abort() (.cold.1) [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 2: 0x10009fbc9 node::Abort() [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 3: 0x10009fd2f node::OnFatalError(char const*, char const*) [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 4: 0x1001e60e0 v8::V8::ToLocalEmpty() [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 5: 0x106807e46 Database::ThrowSqliteError(Addon*, char const*, int) [/Users/andrewchou/GitHub/digidem/mapeo-map-server/node_modules/better-sqlite3/build/Release/better_sqlite3.node]
 6: 0x1068092a1 Statement::JS_run(v8::FunctionCallbackInfo<v8::Value> const&) [/Users/andrewchou/GitHub/digidem/mapeo-map-server/node_modules/better-sqlite3/build/Release/better_sqlite3.node]
 7: 0x10024f438 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 8: 0x10024e9f9 v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(v8::internal::Isolate*, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::HeapObject>, v8::internal::Handle<v8::internal::FunctionTemplateInfo>, v8::internal::Handle<v8::internal::Object>, v8::internal::BuiltinArguments) [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
 9: 0x10024e162 v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArguments, v8::internal::Isolate*) [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
10: 0x1009d3ab9 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
11: 0x100959364 Builtins_InterpreterEntryTrampoline [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
12: 0x100959364 Builtins_InterpreterEntryTrampoline [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]
13: 0x100959364 Builtins_InterpreterEntryTrampoline [/Users/andrewchou/Library/Caches/fnm_multishells/17210_1657814232551/bin/node]

Haven't figured out a minimal reproduction but can make note of the thing that seems to cause it. I have a set of 4 statements that are run within a transaction (better-sqlite3 transaction, not hardcoded). There are other statements in this transaction, but this set seems to be causing issues. The nature of the statements are as follows:

  1. Create a view. This does a join on a subquery and uses some basic json_each stuff
  2. Delete some records using view from (1) to do a subquery for the where clause
  3. Similar to (2) but deleting from a different table
  4. Drop view

Other important notes:

  • WAL mode is enabled
  • Seeing this failure when in the context of tests that I'm running (using tape + ts-node). sometimes the test works and i don't see this error. but i'd say it comes up once every three or four attempts

Entirely possible that this is a red herring. Also, could be approaching this in a non-idiomatic way and maybe there's a better way of doing the above that avoids the issue. Maybe using a CTE might be a better approach, although it seemed to be much slower than using a view since it has to be run for each deletion statement.

Apologies for not having a minimum repro available, but will try for a bit and see if I can create one

Originally posted by @achou11 in https://github.com/WiseLibs/better-sqlite3/issues/281#issuecomment-1184924115

achou11 avatar Jul 14 '22 22:07 achou11

FWIW Node 12 is EOL (and has for several months, and several security issues have not been back-patched to that series). Can you reproduce on a current Node and the latest version of this project?

mceachen avatar Jul 15 '22 22:07 mceachen

FWIW Node 12 is EOL (and has for several months, and several security issues have not been back-patched to that series

Yeah I'm aware of that - unfortunately it's a constraint of the project for the time being 🥲 don't think i specifically tested it locally but I think our CI (which runs this test on Node 12, 14, and 16) encountered the same issue.

will try to upgrade the module and see if that helps. stay tuned...

achou11 avatar Jul 15 '22 22:07 achou11

The stack trace is helpful, but unfortunately I can't diagnose the problem much without a reproducible example. The code path that's failing is working perfectly in all our tests.

JoshuaWise avatar Jul 18 '22 04:07 JoshuaWise

I'll try to spend some time attempting to repro it, although I'm traveling for a bit soon so may be a while 😅

achou11 avatar Jul 18 '22 04:07 achou11

Not a minimal repro but just for me to look back on - here's a snippet from what i'm working with that currently fails (not all the time, but maybe ~50%):

  const deleteStyleTransaction = db.transaction(() => {
     // Some stuff before this...

    db.prepare(
      `
      CREATE VIEW DeletableTilesetIds AS
      SELECT SourceToTilesetIdOuter.value AS tilesetId, Style.id AS styleId
      FROM Style, json_each(Style.sourceIdToTilesetId, '$') AS SourceToTilesetIdOuter
      JOIN (
        SELECT SourceToTilesetIdInner.value AS tilesetId, COUNT(SourceToTilesetIdInner.value) AS freq
        FROM Style, json_each(Style.sourceIdToTilesetId, '$') AS SourceToTilesetIdInner
        GROUP BY SourceToTilesetIdInner.value
      ) AS TilesetIdFreq ON SourceToTilesetIdOuter.value = TilesetIdFreq.tilesetId
      WHERE freq = 1;
    `
    ).run()
    db.prepare(
      'DELETE FROM Tile WHERE tilesetId ' +
        'IN (SELECT tilesetId FROM DeletableTilesetIds WHERE styleId = ?)'
    ).run(id)
    /**
     * Deleting this specific statement seems to prevent the issue from happening 🤔
     */
    db.prepare(
      'DELETE FROM Tileset WHERE id ' +
        'IN (SELECT tilesetId FROM DeletableTilesetIds WHERE styleId = ?)'
    ).run(id)
    db.prepare('DROP VIEW DeletableTilesetIds').run()

    // Some stuff after this...
  })

  deleteStyleTransaction()

achou11 avatar Jul 18 '22 17:07 achou11