ruby-concurrency/concurrent-ruby · critical · RuntimeException

Could not initialize intrinsics

Error message

Could not initialize intrinsics

What it means

Striped64 (the basis of LongAdder/DoubleAdder striped counters) obtains sun.misc.Unsafe.theUnsafe in its static initializer exactly like ConcurrentHashMapV8 does, retrying under AccessController.doPrivileged when a SecurityManager interferes. Failure there is wrapped as RuntimeException("Could not initialize intrinsics"), the class never initializes, and later touches throw NoClassDefFoundError.

Source

Thrown at ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java:336

     *
     * @return a sun.misc.Unsafe
     */
    private static sun.misc.Unsafe getUnsafe() {
        try {
            return sun.misc.Unsafe.getUnsafe();
        } catch (SecurityException se) {
            try {
                return java.security.AccessController.doPrivileged
                        (new java.security
                                .PrivilegedExceptionAction<sun.misc.Unsafe>() {
                            public sun.misc.Unsafe run() throws Exception {
                                java.lang.reflect.Field f = sun.misc
                                        .Unsafe.class.getDeclaredField("theUnsafe");
                                f.setAccessible(true);
                                return (sun.misc.Unsafe) f.get(null);
                            }});
            } catch (java.security.PrivilegedActionException e) {
                throw new RuntimeException("Could not initialize intrinsics",
                        e.getCause());
            }
        }
    }

}

View on GitHub (pinned to 0b88d5ff75)

Solutions

  1. Run on a standard JVM that ships sun.misc.Unsafe (HotSpot/OpenJDK/OpenJ9)
  2. Grant the initializer's requirements in the policy: ReflectPermission "suppressAccessChecks" (plus RuntimePermission "accessDeclaredMembers") for the extension jar
  3. Remove or relax the SecurityManager if feasible
  4. Use the bundled nounsafe Striped64 (com.concurrent_ruby.ext.jsr166e.nounsafe), which relies on atomic field updaters instead of Unsafe
  5. If you maintain a fork, add a VarHandle/atomic-updater fallback to getUnsafe()

Example fix

// before: LongAdder never loads -> Striped64.<clinit> fails
// -> RuntimeException: Could not initialize intrinsics

// after: grant the permission in the .policy file
// grant codeBase "file:<path-to-concurrent-ruby-ext>" {
//   permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
//   permission java.lang.RuntimePermission "accessDeclaredMembers";
// };
// or use the nounsafe build (atomic field updaters, no sun.misc.Unsafe)
Defensive patterns

Strategy: validation

Validate before calling

static boolean unsafeAvailable() {
    try {
        java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        return f.get(null) != null;
    } catch (Throwable t) {
        return false;
    }
}
// probe once at startup; if false, avoid LongAdder/Striped64-backed
// counters and use AtomicLong or the nounsafe build instead

Try / catch

try {
    Object adder = Class.forName("com.concurrent_ruby.ext.jsr166e.LongAdder").newInstance();
} catch (ExceptionInInitializerError e) {
    Throwable c = e.getCause();
    if (c instanceof RuntimeException
            && "Could not initialize intrinsics".equals(((RuntimeException) c).getMessage())) {
        // fall back to AtomicLong-based counters; Striped64 will stay broken (NoClassDefFoundError)
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: First touch of Striped64 — constructing a LongAdder/DoubleAdder or any counter built on cell-striping — when the security policy blocks reflection on sun.misc.Unsafe.theUnsafe, or the runtime (Android/Dalvik, minimal JVMs) has no sun.misc.Unsafe. Initial failure appears as ExceptionInInitializerError; subsequent uses fail with NoClassDefFoundError.

Common situations: JRuby deployments of concurrent-ruby in sandboxed or policy-file-managed environments; nonstandard JVMs lacking sun.misc.Unsafe; runtimes with reflection-blocking agents. The gem's nounsafe build of Striped64 replaces Unsafe with AtomicIntegerFieldUpdater/AtomicLongFieldUpdater for exactly this case.

Related errors


AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21). Data as JSON: /api/errors/612e68c40749ec13. Report an issue: GitHub.