apache/beam · error · LinkageError

${e.getMessage()}

Error message

${e.getMessage()}

What it means

While selecting a class-loading strategy for the generated invoker, any ReflectiveOperationException (e.g. from Lookup.privateLookupIn) is wrapped in a LinkageError whose message is just the original exception's message. It signals the JVM could not perform the reflective lookup needed to enable code generation.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/ByteBuddyDoFnInvokerFactory.java:718

        Method privateLookupIn =
            methodHandles.getMethod(
                "privateLookupIn",
                Class.class,
                Class.forName("java.lang.invoke.MethodHandles$Lookup"));

        Object privateLookup =
            checkStateNotNull(
                privateLookupIn.invoke(nullObjectForStaticMethodInvocation, targetClass, lookup),
                "MethodHandles.Lookup.privateLookupIn not available");
        strategy = ClassLoadingStrategy.UsingLookup.of(privateLookup);
      } else if (ClassInjector.UsingReflection.isAvailable()) {
        strategy = ClassLoadingStrategy.Default.INJECTION;
      } else {
        throw new IllegalStateException("No code generation strategy available");
      }
      return strategy;
    } catch (ReflectiveOperationException e) {
      throw new LinkageError(e.getMessage(), e);
    }
  }

  private static Implementation getRestrictionCoderDelegation(
      TypeDescription doFnType, DoFnSignature signature) {
    if (signature.processElement().isSplittable()) {
      if (signature.getRestrictionCoder() == null) {
        checkStateNotNull(
            signature.getInitialRestriction(),
            "@GetRestrictionCoder provided but @GetInitialRestriction not provided:"
                + " please add @GetInitialRestriction");
        return MethodDelegation.to(
            new DefaultRestrictionCoder(signature.getInitialRestriction().restrictionT()));
      } else {
        return new DowncastingParametersMethodDelegation(
            doFnType, signature.getRestrictionCoder().targetMethod());
      }
    } else {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add --add-opens / --add-reads JVM flags granting access to the relevant module/package (e.g. --add-opens java.base/java.lang=ALL-UNNAMED).
  2. Move the DoFn classes to the classpath (unnamed module) instead of a named module.
  3. Read e.getMessage() in the LinkageError to identify which reflective call failed and fix access for it.

Example fix

// before
java --module-path mods -m app/Main // LinkageError: access denied
// after
java --module-path mods --add-reads app=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED -m app/Main
Defensive patterns

Strategy: try-catch

Try / catch

try {
  invoker = ByteBuddyDoFnInvokerFactory.newByteBuddyInvoker(fn);
} catch (LinkageError e) {
  LOG.error("Reflective lookup failed: " + e.getMessage(), e);
  throw e;
}

Prevention

When it happens

Trigger: Lookup.privateLookupIn(targetClass, lookup) throws due to module access denial, or another reflective step in strategy selection fails on the current JVM.

Common situations: Java 9+ strong encapsulation without --add-opens; DoFn classes in a named module without the required --add-reads; container security managers.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/a37cf5f21a31790c. Report an issue: GitHub.