pinpoint-apm/pinpoint · critical · IllegalStateException

Cannot access ClassLoader.defineClass(String, byte[], int, i

Error message

Cannot access ClassLoader.defineClass(String, byte[], int, int)

What it means

ReflectionDefineClass obtains a reflective handle to the protected ClassLoader.defineClass(String, byte[], int, int) method in a static initializer and calls setAccessible(true). If the JVM refuses (method missing or reflective access denied by the module system / SecurityManager), an IllegalStateException is thrown during class initialization, failing agent startup before any plugin is loaded. Pinpoint uses this to define plugin classes into arbitrary application classloaders.

Source

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

import org.apache.logging.log4j.Logger;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author Woonduk Kang(emeroad)
 */
final class ReflectionDefineClass implements DefineClass {

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

    private static final Method DEFINE_CLASS;
    static {
        try {
            DEFINE_CLASS = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
            DEFINE_CLASS.setAccessible(true);
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException("Cannot access ClassLoader.defineClass(String, byte[], int, int)", 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(classLoader, name, bytes, 0, bytes.length);
        } 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)

Solutions

  1. Add the required JVM flags: --add-opens java.base/java.lang=ALL-UNNAMED (plus any others listed in the agent startup log) to the application's launch command.
  2. Remove or relax the SecurityManager policy so ReflectPermission("suppressAccessChecks") is granted to the pinpoint agent codebase.
  3. Verify the pinpoint agent version is certified for your JDK; upgrade the agent if running on a newer JDK that changed access rules.
  4. If the SecurityManager is not actually required, disable it (e.g. -Djava.security.manager=allow is not enough on newer JDKs — remove the manager).
  5. Confirm the JVM is a standard OpenJDK/HotSpot build supported by pinpoint, not a hardened variant stripping protected members.

Example fix

// before
java -jar app.jar
// after
java --add-opens java.base/java.lang=ALL-UNNAMED -javaagent:$AGENT_HOME/pinpoint-bootstrap.jar -jar app.jar
Defensive patterns

Strategy: validation

Validate before calling

// preflight check before enabling the pinpoint agent on a new JVM
boolean canDefine = false;
try {
    Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
    m.setAccessible(true);
    canDefine = true;
} catch (ReflectiveOperationException e) {
    System.err.println("Agent unsupported: need --add-opens java.base/java.lang=ALL-UNNAMED");
}
if (!canDefine) throw new IllegalStateException("JVM blocks ClassLoader.defineClass reflection; add --add-opens flags");

Type guard

static boolean supportsReflectiveDefineClass() {
    try {
        Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        m.setAccessible(true);
        return true;
    } catch (ReflectiveOperationException | SecurityException e) {
        return false;
    }
}

Try / catch

try {
    agentBootstrap.start();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Cannot access ClassLoader.defineClass")) {
        System.err.println("Restart JVM with: --add-opens java.base/java.lang=ALL-UNNAMED");
    } else throw e;
}

Prevention

When it happens

Trigger: The agent runs on a JVM where ClassLoader.getDeclaredMethod("defineClass", ...) fails or setAccessible(true) is rejected: JDK 9+ with strong encapsulation and no --add-opens for java.lang, a SecurityManager denying ReflectPermission("suppressAccessChecks"), or an exotic/hardened JVM that hides defineClass.

Common situations: Upgrading the target app to JDK 16+ where default strong encapsulation blocks setAccessible on JDK internals; containers applying legacy SecurityManager policies; running the agent on an unsupported or custom JDK build.

Related errors


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