grpc/grpc-java · error · IllegalArgumentException

TARGET_ANDROID_USER NameResolver.Arg requires SDK_INT >= R a

Error message

TARGET_ANDROID_USER NameResolver.Arg requires SDK_INT >= R and @SystemApi visibility

What it means

IntentNameResolver resolves targets in a different Android user profile via TARGET_ANDROID_USER NameResolver.Arg. Resolving a target user requires Context.createContextAsUser, which is only available as @SystemApi from Android SDK_INT >= R (30). When reflection to invoke that hidden API fails, the resolver throws this IllegalArgumentException rather than silently ignoring the target user.

Source

Thrown at binder/src/main/java/io/grpc/binder/internal/IntentNameResolver.java:104

    Context context =
        checkNotNull(args.getArg(ApiConstants.SOURCE_ANDROID_CONTEXT), "SOURCE_ANDROID_CONTEXT")
            .getApplicationContext();
    this.targetUserContext =
        targetUser != null ? createContextForTargetUserOrThrow(context, targetUser) : context;
    // This Executor is nominally optional but all grpc-java Channels provide it since 1.25.
    this.offloadExecutor =
        checkNotNull(args.getOffloadExecutor(), "NameResolver.Args.getOffloadExecutor()");
    // Ensures start()'s work runs before resolve()'s' work, and both run before shutdown()'s.
    this.sequentialExecutor = MoreExecutors.newSequentialExecutor(offloadExecutor);
    this.syncContext = args.getSynchronizationContext();
    this.serviceConfigParser = args.getServiceConfigParser();
  }

  private static Context createContextForTargetUserOrThrow(Context context, UserHandle targetUser) {
    try {
      return createContextAsUser(context, targetUser, /* flags= */ 0); // @SystemApi since R.
    } catch (ReflectiveOperationException e) {
      throw new IllegalArgumentException(
          "TARGET_ANDROID_USER NameResolver.Arg requires SDK_INT >= R and @SystemApi visibility");
    }
  }

  @Override
  public void start(Listener2 listener) {
    checkState(this.listener == null, "Already started!");
    checkState(!shutdown, "Resolver is shutdown");
    this.listener = checkNotNull(listener);
    sequentialExecutor.execute(this::registerReceiver);
    resolve();
  }

  @Override
  public void refresh() {
    checkState(listener != null, "Not started!");
    resolve();
  }

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Only set a TARGET_ANDROID_USER arg when Build.VERSION.SDK_INT >= Build.VERSION_CODES.R and the app has system/privileged visibility.
  2. Fall back to resolving within the current user (omit the target-user arg) when the platform requirement is unmet.
  3. If cross-user is required, run on API 30+ with a privileged (system-signed, PRIVILEGED_SIGNATURE) install.

Example fix

// before
resolverArgsBuilder.setNameResolverArg(IntentNameResolver.TARGET_ANDROID_USER, otherUserHandle);
// after
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && isPrivilegedApp()) {
  resolverArgsBuilder.setNameResolverArg(IntentNameResolver.TARGET_ANDROID_USER, otherUserHandle);
} else {
  // resolve in current user
}
Defensive patterns

Strategy: validation

Validate before calling

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || !isSystemVisible()) {
  throw new IllegalStateException("TARGET_ANDROID_USER requires SDK_INT >= R and @SystemApi visibility");
}

Try / catch

try {
  resolver.start(listener);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("TARGET_ANDROID_USER")) { /* fall back to current user resolution */ }
}

Prevention

When it happens

Trigger: Using IntentNameResolver with a NameResolver.Arg targeting a different Android user on a device running SDK_INT < 30 (pre-R), or on a build where the app lacks @SystemApi / system-privilege visibility so createContextAsUser throws ReflectiveOperationException.

Common situations: Running a cross-user gRPC-binder app on Android 10 or older; shipping a consumer (non-system / non-privileged) APK that attempts TARGET_ANDROID_USER resolution; ROM or SDK-version changes that remove API visibility.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/1d56d0fdd2ad755a. Report an issue: GitHub.