openclaw - 💡(How to fix) Fix node:sqlite fails on ARM64 (aarch64) in containers — SQLITE_BUSY on all file-backed databases [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#60084Fetched 2026-04-08 02:36:34
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

OpenClaw's memory search is completely broken on ARM64 (aarch64) when running in Kubernetes containers. The root cause is that node:sqlite's DatabaseSync cannot acquire POSIX advisory file locks (fcntl F_SETLK) on ARM64 Linux in containerized environments. Every SQL operation on file-backed databases fails with SQLITE_BUSY (errcode 5). In-memory databases (:memory:) work fine.

This affects all file-based SQLite operations: memory search, memory indexing, task registry (runs.sqlite), and any extension using the node:sqlite built-in.

Error Message

Inside an OpenClaw container on ARM64:

node -e " const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync('/tmp/test.sqlite'); db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)'); "

→ SqliteError: database is locked (SQLITE_BUSY, errcode 5)

In-memory works fine:

node -e " const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync(':memory:'); db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)'); console.log('OK'); "

→ OK

Root Cause

OpenClaw's memory search is completely broken on ARM64 (aarch64) when running in Kubernetes containers. The root cause is that node:sqlite's DatabaseSync cannot acquire POSIX advisory file locks (fcntl F_SETLK) on ARM64 Linux in containerized environments. Every SQL operation on file-backed databases fails with SQLITE_BUSY (errcode 5). In-memory databases (:memory:) work fine.

Fix Action

Fix / Workaround

Current workaround

We built a custom image that:

  1. Installs better-sqlite3 with native ARM64 prebuilds
  2. Uses NODE_OPTIONS=--require to monkey-patch Module._load, intercepting require("node:sqlite") and redirecting to a compatibility shim
  3. The shim loads SQLite files into memory via fs.readFileSync() + new Database(buffer), operates purely in-memory, and persists via db.serialize() + fs.writeFileSync() on close and every 30 seconds

Any of these would eliminate the need for our 3-layer workaround and benefit all ARM64 OpenClaw users running in containers.

Code Example

# Inside an OpenClaw container on ARM64:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('/tmp/test.sqlite');
db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)');
"
# → SqliteError: database is locked (SQLITE_BUSY, errcode 5)

# In-memory works fine:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync(':memory:');
db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)');
console.log('OK');
"
# → OK

---

function requireNodeSqlite() {
  installProcessWarningFilter();
  try {
    return require("node:sqlite");
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    throw new Error(
      `SQLite support is unavailable in this Node runtime. ${message}`,
      { cause: err }
    );
  }
}
RAW_BUFFERClick to expand / collapse

Summary

OpenClaw's memory search is completely broken on ARM64 (aarch64) when running in Kubernetes containers. The root cause is that node:sqlite's DatabaseSync cannot acquire POSIX advisory file locks (fcntl F_SETLK) on ARM64 Linux in containerized environments. Every SQL operation on file-backed databases fails with SQLITE_BUSY (errcode 5). In-memory databases (:memory:) work fine.

This affects all file-based SQLite operations: memory search, memory indexing, task registry (runs.sqlite), and any extension using the node:sqlite built-in.

Environment

  • OpenClaw version: 2026.4.1
  • Node.js: v24.14.0 (bundled in OpenClaw image)
  • Architecture: ARM64 / aarch64 (Orange Pi 5, Rockchip RK3588S)
  • Kernel: Linux 6.8.0-106-generic
  • Container runtime: containerd via Kubernetes v1.31.14
  • Filesystem: ext4 on Longhorn iSCSI PVs AND tmpfs emptyDir — both fail identically

Reproduction

# Inside an OpenClaw container on ARM64:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync('/tmp/test.sqlite');
db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)');
"
# → SqliteError: database is locked (SQLITE_BUSY, errcode 5)

# In-memory works fine:
node -e "
const { DatabaseSync } = require('node:sqlite');
const db = new DatabaseSync(':memory:');
db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)');
console.log('OK');
"
# → OK

Key findings

  1. Not specific to node:sqlite — we installed better-sqlite3 (which bundles its own compiled SQLite with native ARM64 prebuilds) and it fails identically. This rules out a bug in Node's SQLite bindings.

  2. Not filesystem-related — fails on Longhorn PVs, emptyDir mounts, and /tmp. Even brand-new empty databases on fresh filesystems fail.

  3. Not a contention issue — single process, single connection, no WAL, no other processes accessing the file. The DatabaseSync constructor succeeds (file handle opens), but the first SQL statement fails (because it needs at least a shared lock via fcntl).

  4. In-memory databases work perfectlynew DatabaseSync(':memory:') and new Database(buffer) (better-sqlite3) both work. This confirms the issue is specifically in the POSIX advisory locking layer.

  5. Basic file I/O works — readFileSync, writeFileSync, file descriptor operations all succeed. Shell flock also works. The failure is specific to fcntl(F_SETLK) with byte-range locks (which SQLite uses internally).

  6. Previously working — memory was last written successfully on March 26 under OpenClaw 2026.3.24. The issue appeared after upgrading to 2026.4.1.

Impact

Memory search is the primary way agents recall context across sessions. With it broken, both our agents (running 24/7 in production) lost all semantic memory recall. The task registry (runs.sqlite) was also stuck at 0 bytes.

Current workaround

We built a custom image that:

  1. Installs better-sqlite3 with native ARM64 prebuilds
  2. Uses NODE_OPTIONS=--require to monkey-patch Module._load, intercepting require("node:sqlite") and redirecting to a compatibility shim
  3. The shim loads SQLite files into memory via fs.readFileSync() + new Database(buffer), operates purely in-memory, and persists via db.serialize() + fs.writeFileSync() on close and every 30 seconds

This works but is fragile — it has 6 failure points and will break on OpenClaw upgrades.

Proposed fix

Make the SQLite driver configurable or add a fallback. The current code in packages/memory-host-sdk/src/host/sqlite.ts hardcodes require("node:sqlite") with no abstraction:

function requireNodeSqlite() {
  installProcessWarningFilter();
  try {
    return require("node:sqlite");
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    throw new Error(
      `SQLite support is unavailable in this Node runtime. ${message}`,
      { cause: err }
    );
  }
}

Options (in order of preference):

  1. Add better-sqlite3 as a fallback — try node:sqlite, catch failure, automatically fall back to better-sqlite3. Zero config needed, self-healing. better-sqlite3 has mature ARM64 support and nearly identical sync API.

  2. Make the driver configurable — env var like OPENCLAW_SQLITE_DRIVER=better-sqlite3 for users who know their platform needs it.

  3. Add a runtime locking probe — before using node:sqlite for real databases, test fcntl on a temp file. If it fails, switch to better-sqlite3 automatically.

Any of these would eliminate the need for our 3-layer workaround and benefit all ARM64 OpenClaw users running in containers.

Additional context

  • We've confirmed this is NOT a known Node.js issue — searched the nodejs/node tracker extensively, no matching reports for single-process SQLITE_BUSY on ARM64
  • Node 24.14.0 is the latest 24.x release; no newer patch exists
  • node:sqlite was promoted from experimental in Node 24, but the underlying SQLite VFS still uses fcntl for POSIX advisory locking
  • Our cluster runs 4 ARM64 nodes (Orange Pi 5, RK3588S) with Kubernetes v1.31.14 and containerd
  • The container security context includes readOnlyRootFilesystem: true, capabilities.drop: ALL, and seccompProfile: RuntimeDefault — none of these should affect fcntl

Happy to contribute a PR for any of the proposed fixes once we align on the preferred approach.

extent analysis

TL;DR

The most likely fix for the SQLite issue on ARM64 in Kubernetes containers is to add better-sqlite3 as a fallback driver to handle POSIX advisory locking failures.

Guidance

  • Identify the root cause of the issue: The problem lies in the POSIX advisory locking layer, specifically with fcntl F_SETLK on ARM64 Linux in containerized environments.
  • Consider the proposed fixes: Adding better-sqlite3 as a fallback driver, making the driver configurable, or adding a runtime locking probe are potential solutions.
  • Evaluate the trade-offs: Each proposed fix has its advantages and disadvantages, such as added complexity or potential performance impacts.
  • Test and verify: Any implemented fix should be thoroughly tested to ensure it resolves the issue and does not introduce new problems.

Example

// Example of adding better-sqlite3 as a fallback driver
function requireNodeSqlite() {
  try {
    return require("node:sqlite");
  } catch (err) {
    try {
      return require("better-sqlite3");
    } catch (fallbackErr) {
      throw new Error(
        `SQLite support is unavailable in this Node runtime. ${err.message}`,
        { cause: err }
      );
    }
  }
}

Notes

  • The issue is specific to ARM64 architecture and containerized environments.
  • The proposed fixes aim to address the POSIX advisory locking issue, but may require additional testing and validation.
  • The choice of fix will depend on the specific requirements and constraints of the OpenClaw project.

Recommendation

Apply the workaround of adding better-sqlite3 as a fallback driver, as it provides a self-healing solution with zero configuration needed. This approach allows for a more robust and reliable SQLite driver, reducing the likelihood of failures due to POSIX advisory locking issues.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING