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
- Run on a standard JVM that ships sun.misc.Unsafe (HotSpot/OpenJDK/OpenJ9)
- Grant the initializer's requirements in the policy: ReflectPermission "suppressAccessChecks" (plus RuntimePermission "accessDeclaredMembers") for the extension jar
- Remove or relax the SecurityManager if feasible
- Use the bundled nounsafe Striped64 (com.concurrent_ruby.ext.jsr166e.nounsafe), which relies on atomic field updaters instead of Unsafe
- 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
- Probe sun.misc.Unsafe availability before first counter use in locked-down environments
- Grant ReflectPermission \"suppressAccessChecks\" to the extension jar in the policy
- Prefer the nounsafe Striped64 build (atomic field updaters) where Unsafe is unavailable
- After one init failure the class never loads again in that JVM — restart after fixing the policy
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
- Could not initialize intrinsics
- Required array size too large
- Required array size too large
- cannot enqueue nil
- NullPointerException
AI-assisted analysis of ruby-concurrency/concurrent-ruby@0b88d5ff75 (2026-08-21).
Data as JSON: /api/errors/612e68c40749ec13.
Report an issue: GitHub.