pinpoint-apm/pinpoint · critical · IllegalStateException

Cannot access sun.misc.Unsafe.defineClass

Error message

Cannot access sun.misc.Unsafe.defineClass

What it means

IllegalStateException raised in UnsafeDefineClass's static initializer when reflective access to sun.misc.Unsafe.defineClass fails. Pinpoint uses Unsafe.defineClass to inject classes into arbitrary classloaders; this API is inaccessible on JDKs where sun.misc.Unsafe internals are encapsulated or removed.

Solutions

  1. Use a Pinpoint agent version that supports your JDK (newer versions use MethodHandles/Lookup.defineClass instead of Unsafe).
  2. Add JVM flags: --add-opens java.base/jdk.internal.misc=ALL-UNNAMED and appropriate --add-exports for jdk.unsupported.
  3. Run on JDK 8 where sun.misc.Unsafe.defineClass is accessible if you must use an old agent version.
  4. Check the wrapped ReflectiveOperationException cause to see whether theUnsafe or defineClass is the missing member.

Example fix

// before (JDK 17, no flags)
java -jar pinpoint-bootstrap.jar ...
// after
java --add-opens java.base/java.lang=ALL-UNNAMED --add-exports jdk.unsupported/sun.misc=ALL-UNNAMED -jar pinpoint-bootstrap.jar ...
Defensive patterns

Strategy: validation

Validate before calling

// verify accessibility at startup
try {
  Class<?> u = Class.forName("sun.misc.Unsafe");
  Field f = u.getDeclaredField("theUnsafe"); f.setAccessible(true);
} catch (Throwable t) { /* Unsafe path unavailable: use --add-opens or upgrade agent */ }

Try / catch

try { UnsafeDefineClass h = new UnsafeDefineClass(); } catch (IllegalStateException e) { logger.error("Unsafe.defineClass unavailable on this JVM; upgrade agent or add --add-opens flags", e); }

Prevention

When it happens

Trigger: Class initialization of UnsafeDefineClass on a JVM where theUnsafe field or defineClass(String, byte[], int, int, ClassLoader, ProtectionDomain) cannot be resolved via reflection - typically JDK 9+ with strong encapsulation, or a JVM without sun.misc.Unsafe.

Common situations: Running the Pinpoint agent on JDK 9/11/17+ where --add-exports/--add-opens for jdk.unsupported is not set, running on a non-HotSpot JVM, or using a hardened JVM that blocks sun.misc.Unsafe reflection.

Understand the failure class

Background: "is deprecated and will be removed" — deprecation warnings for old API names, keywords, and options, and how to migrate before the removal release — this error's family across 29 libraries.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/f60d7fb05d0aca81. Report an issue: GitHub.

Appendix: source

Thrown at agent-module/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/UnsafeDefineClass.java:48

 * resolved reflectively and must not be reached on JDK 9+.
 */
final class UnsafeDefineClass implements DefineClass {

    private final Logger logger = LogManager.getLogger(this.getClass());

    private static final Object UNSAFE;
    private static final Method DEFINE_CLASS;

    static {
        try {
            final Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
            final Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            UNSAFE = theUnsafe.get(null);
            DEFINE_CLASS = unsafeClass.getMethod("defineClass",
                    String.class, byte[].class, int.class, int.class, ClassLoader.class, ProtectionDomain.class);
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException("Cannot access sun.misc.Unsafe.defineClass", e);
        }
    }

    @Override
    public Class<?> defineClass(ClassLoader classLoader, String name, byte[] bytes) {
        if (logger.isDebugEnabled()) {
            logger.debug("define class:{} cl:{}", name, classLoader);
        }
        try {
            return (Class<?>) DEFINE_CLASS.invoke(UNSAFE, name, bytes, 0, bytes.length, classLoader, null);
        } catch (InvocationTargetException e) {
            // unwrap: the message of the LinkageError/ClassFormatError thrown by the VM is on the cause
            final Throwable cause = e.getCause() != null ? e.getCause() : e;
            throw handleDefineClassFail(classLoader, name, cause);
        } catch (ReflectiveOperationException e) {
            throw handleDefineClassFail(classLoader, name, e);
        }
    }

View on GitHub (pinned to 744c3d3075)