Skip to content

Bug: @ladybugdb/core lbugjs.node fails to initialize in Node SEA executable on Windows x64 #1015

Description

@TechQuery

Ladybug version

@ladybugdb/core 0.20.4

What operating system are you using?

Windows x64

What happened?

When @ladybugdb/core is used from a Node.js Single Executable Application (SEA) built with pnpm pack-app, the native module file is found on disk but fails during process.dlopen() initialization:

[database] graph initializing
[database] graph failed: A dynamic link library (DLL) initialization routine failed.
<repo>\packages\command\dist-app\win32-x64\lbugjs.node

The same bundled CommonJS entry works under normal node, and the same SEA executable can initialize other native database dependencies when their native bindings are copied next to the executable:

# normal node running the bundled CJS entry
[database] relational initialized      # better-sqlite3
[database] vector initialized          # @lancedb/lancedb
[database] graph initialized           # @ladybugdb/core

# Node SEA executable from the same CJS entry
[database] relational initialized      # better-sqlite3
[database] vector initialized          # @lancedb/lancedb
[database] graph failed: A dynamic link library (DLL) initialization routine failed.
...\dist-app\win32-x64\lbugjs.node

This suggests the issue is not that lbugjs.node is missing. The file is present beside the executable and @ladybugdb/core reaches the process.dlopen(lbugjs.node) path, but the DLL initialization routine fails only under the SEA executable host.

Are there known steps to reproduce?

Minimal shape of the repro:

import { Connection, Database } from '@ladybugdb/core';

const database = new Database(':memory:');
await database.init();
const connection = new Connection(database);
await connection.init();

await connection.close();
await database.close();

In the downstream project this is built as follows:

# build a CJS entry with tsdown
pnpm --filter @engineering-tender-ai/command build:sea

# normal node works
node packages/command/dist-sea/command.cjs -h

# build SEA executable
pnpm --filter @engineering-tender-ai/command pack-sea --target=win32-x64

# SEA executable fails only on LadybugDB native initialization
packages/command/dist-app/win32-x64/engineering-tender-ai.exe -h

The SEA packaging command uses Node 26.7.0:

pnpm pack-app \
  --entry ./dist-sea/command.cjs \
  --runtime node@26.7.0 \
  --target win32-x64 \
  --output-dir dist-app \
  --output-name engineering-tender-ai

The downstream package copies lbugjs.node next to the executable before running it. Directory layout at runtime:

dist-app/win32-x64/
  engineering-tender-ai.exe
  lbugjs.node

For comparison, the same SEA executable also copies native assets for better-sqlite3 and @lancedb/lancedb; those can be initialized successfully after their native loader paths are pointed at the copied assets.

Relevant loader behavior

The published package loader uses process.dlopen() directly:

const lbugNativeModule = { exports: {} };
const modulePath = join(__dirname, 'lbugjs.node');

if (process.platform === 'linux') {
  process.dlopen(
    lbugNativeModule,
    modulePath,
    constants.RTLD_LAZY | constants.RTLD_GLOBAL
  );
} else {
  process.dlopen(lbugNativeModule, modulePath);
}

module.exports = lbugNativeModule.exports;

This is similar in spirit to the Electron-on-Windows native host issue discussed in #383: plain Node can load the native addon, but a non-standard Node host executable fails during native loading/initialization.

Expected behavior

@ladybugdb/core should either:

  1. load successfully from a Node SEA executable when lbugjs.node is present on the real filesystem next to the executable, or
  2. document that Node SEA / embedded Node hosts are unsupported on Windows and explain any required build/link flags or runtime DLL dependencies.

Additional notes

I searched existing issues and did not find an exact Node SEA / single executable report. The closest prior discussion appears to be #383 for Electron on Windows, where the problem also involved native loading under a non-standard host executable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions