Skip to content

[Bug]: rocksdb-native prebuilds DT_NEEDED-link libatomic.so.1; worker cannot start on slim Linux images (follow-up to #3853) #4290

Description

@hevans714

Split out of #3853 at @victorchimakanu's request in the closing comment there: "Worth a focused
issue scoped to rocksdb-native's DT_NEEDED."
This is that issue. The tree-wide preflight named
alongside it is deliberately not in scope here — it is the class, this is one instance.

Summary

rocksdb-native's Linux prebuilds declare libatomic.so.1 as a required shared library.
libatomic1 is not installed in node:22-slim, debian:12-slim or ubuntu:24.04, so on a
clean slim image the bare worker aborts during startup and no model of any modality will
load
— the same failure shape as the libvulkan half of #3853, on an unrelated package.

This is not covered by the fix that closed #3853. @qvac/diffusion-cpp 0.21.0 makes the Vulkan
backend a dlopen'd module, which resolves that instance. rocksdb-native is untouched by it.

Reproduction

Clean node:22-slim, npm install -g @qvac/cli@0.12.0 (resolves @qvac/sdk 0.18.x), with
libvulkan1 already installed
so the #3853 workaround is in place:

[cause]: Error: libatomic.so.1: cannot open shared object file: No such file or directory
    at require.addon (bare-module/index.js:822:30)
    at rocksdb-native/binding.js:3:26
  code: 'CANNOT_LOAD',
  href: 'file:///usr/local/.../rocksdb-native/prebuilds/linux-arm64/rocksdb-native.bare'
...
code: 50204

apt-get install -y libatomic1 fixes it — same shape as the libvulkan1 workaround.

The trace stops at rocksdb-native/lib/column-family.js, so all we can support is that the load
happens during worker startup. We cannot say from the trace which package triggers it; see
"What we cannot say" below.

Verified against the currently published artifacts (2026-09-06)

rocksdb-native is still 3.17.4 — the same version as when this was first reported on
#3853 (2026-08-24), so nothing has moved underneath it. We unpacked the published tarball and
parsed the DT_NEEDED entries out of each prebuild's ELF .dynamic section rather than reading
a changelog:

prebuild DT_NEEDED
linux-arm64/rocksdb-native.bare libatomic.so.1, libstdc++.so.6, libm.so.6, libgcc_s.so.1, libc.so.6
linux-arm64/rocksdb-native.node libatomic.so.1, libstdc++.so.6, libm.so.6, libgcc_s.so.1, libc.so.6
linux-x64/rocksdb-native.bare libatomic.so.1, libstdc++.so.6, libm.so.6, libgcc_s.so.1, libc.so.6, ld-linux-x86-64.so.2
linux-x64/rocksdb-native.node libatomic.so.1, libstdc++.so.6, libm.so.6, libgcc_s.so.1, libc.so.6, ld-linux-x86-64.so.2

Two details that were not in the original report:

  • It is all four Linux artifacts, both architectures and both the .bare and .node
    flavours — not just the arm64 .bare the original trace happened to name.
  • It is Linux-specific. The android-arm64 and android-x64 prebuilds link
    libc++_shared.so and need no libatomic; darwin, iOS and win32 are unaffected. So this is a
    property of how the Linux prebuilds are linked, not of the source.

Why the #3853 fix does not cover this

rocksdb-native is not a modality plugin addon at all — it is not among the 13 */plugin
subpaths @qvac/sdk exports on main. It arrives through the storage family, which the SDK
depends on directly.

(The packages/bare-sdk/scripts/plugin-addons.mjs list referenced earlier on #3853 no longer
exists on main — packages/bare-sdk is gone — so the plugin subpath exports are the current
equivalent.) Confirmed against @qvac/sdk 0.18.2 as published:

@qvac/registry-client ^0.6.1     corestore  ^7.4.5
hyperdrive            ^13.0.1    hyperswarm ^4.14.0

and hyperdb (rocksdb-native@^3.0.0) and hypercore-storage (rocksdb-native@^3.11.0) each
declare it directly — they are siblings, not a chain.

The consequence for whoever picks this up: a guard scoped to the plugin addon list, or a lazy
plugin-import fix, would not have caught this. That is the substance of @victorchimakanu's
2026-08-25 comment on #3853 — two system libraries, two unrelated addon families, the second one
found on a clean image of the release published that same morning.

What we cannot say

Which of the four paths actually triggers the load. There is more than one route to the same
prebuild and the stack trace does not name the caller. We are not claiming it is hyperdb, and
an earlier version of this report said "hyperdbhypercore-storage", which was wrong and
was corrected on the original thread.

Possible fixes, in the order we would want them

  1. Link it statically or drop the dependency. libatomic is usually pulled in when the
    compiler emits calls to __atomic_* helpers for wide or unaligned atomics rather than
    inlining them. -Wl,--as-needed plus libatomic.a, or raising the target so the atomics
    inline, would remove the runtime requirement entirely. This is the only fix that needs
    nothing from operators.
  2. Document it. If the link is load-bearing, libatomic1 belongs next to libvulkan1 in
    whatever install guidance ships for slim images.
  3. Fail usefully. QVAC-23774 fix: surface preload failure cause and refuse to start when all preloads fail #4129 improved this by surfacing worker stderr instead of only the timeout,
    which is what made this one findable at all. A startup check that names the addon and the
    missing library would turn a 30-second mystery into a one-line message.

Environment

  • node:22-slim, @qvac/cli@0.12.0, @qvac/sdk 0.18.x, rocksdb-native 3.17.4

  • linux/arm64 (Docker on Apple Silicon) and linux/amd64 (Ubuntu 24.04, 2 vCPU / 7 GB, no GPU,
    no graphics stack) — both reproduce, both are fixed by libatomic1

  • Base images re-checked 2026-09-06, both architectures. In every case the libatomic1
    package is not installed, libatomic.so.1 is not resolvable by the loader, and no copy of the
    file exists anywhere on the filesystem:

    image linux/arm64 linux/amd64
    node:22-slim absent absent
    debian:12-slim absent absent
    ubuntu:24.04 absent absent
  • The DT_NEEDED table above was re-verified against the published tarball on 2026-09-06. The
    runtime trace under "Reproduction" is from a real install on 2026-08-24; rocksdb-native has
    not been republished since, so the static facts above describe that same artifact.

Offer

Same standing offer as on #3853, and it still holds. We run QVAC in production on CPU-only boxes
in both architectures with a real cross-language workload. Stripping a library from a warm image
takes about a second, so we can run a patched build against the empty-libatomic1 case in both
arches the same day. Say the word and it is yours.

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