pinpoint-apm/pinpoint · error · NullPointerException

handler

Error message

handler

What it means

UnsafeDelegatorJava8.register installs the global LambdaBytecodeHandler used to instrument lambda invocations on Java 8+. It refuses null with NullPointerException("handler") and only accepts the first registration; subsequent registrations fail (return false) because the field is already set.

Source

Thrown at agent-module/bootstraps/bootstrap-core/src/main/java/com/navercorp/pinpoint/bootstrap/lambda/UnsafeDelegatorJava8.java:31

 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.navercorp.pinpoint.bootstrap.lambda;

import com.navercorp.pinpoint.bootstrap.instrument.lambda.LambdaBytecodeHandler;
import sun.misc.Unsafe;

/**
 * @author Woonduk Kang(emeroad)
 */
public class UnsafeDelegatorJava8 {
    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
    private static LambdaBytecodeHandler handler;

    public static boolean register(LambdaBytecodeHandler handler) {
        if (handler == null) {
            throw new NullPointerException("handler");
        }
        final LambdaBytecodeHandler localCopy = UnsafeDelegatorJava8.handler;
        if (localCopy == null) {
            UnsafeDelegatorJava8.handler = handler;
            return true;
        } else {
            System.err.println("LambdaBytecodeHandler already registered");
            return false;
        }
    }

    public static Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
        if (hostClass == null || data == null) {
            throw new NullPointerException();
        }
        if (hostClass.isArray() || hostClass.isPrimitive()) {
            throw new IllegalArgumentException();
        }

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Ensure register is called exactly once with a non-null handler, guarded by the boolean return value
  2. Check the return value of register(): false means another handler already owns the slot
  3. In tests, isolate registration to a single setup or use a fresh JVM/classloader

Example fix

// before
UnsafeDelegatorJava8.register(null); // NPE
// after
if (handler != null && !UnsafeDelegatorJava8.register(handler)) {
    logger.warn("lambda handler already registered");
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (handler == null) throw new IllegalArgumentException("handler must not be null");

Type guard

boolean registerSafe(LambdaBytecodeHandler h) { return h != null && UnsafeDelegatorJava8.register(h); }

Try / catch

try {
    boolean installed = UnsafeDelegatorJava8.register(handler);
    if (!installed) logger.warn("lambda handler already registered; ignoring");
} catch (NullPointerException e) {
    if ("handler".equals(e.getMessage())) {
        logger.error("register(null) is not allowed", e);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling UnsafeDelegatorJava8.register(null); or attempting to register a second handler when one was already installed earlier in the JVM lifetime.

Common situations: Bootstrap ordering bugs where registration code runs twice; two agent components competing to install the lambda handler; unit tests leaking a previously registered handler in the same JVM.

Related errors


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