grpc/grpc-java · error · IllegalArgumentException

Authorization policy should be a JSON object. Found: null

Error message

Authorization policy should be a JSON object. Found: null

What it means

AuthorizationPolicyTranslator.translate() parses a JSON string representing a gRPC authorization policy. JsonParser.parse() can return null (or a non-Map scalar like a string/number) when the input is not a JSON object; since a valid policy must be an object with fields like 'name' and rules, translate() throws IllegalArgumentException immediately with the actual parsed type in the message.

Solutions

  1. Verify the policy string is non-empty and parses to a JSON object before calling translate: JsonParser.parse(policy) instanceof Map
  2. Check the file/env-var source actually contains the policy JSON (print it before translating)
  3. If the policy is YAML, convert it to JSON first; gRPC authz policies must be JSON objects
  4. Wrap translate() in try-catch for IllegalArgumentException and surface a clear config-loading error

Example fix

// before
List<RBAC> rbacs = AuthorizationPolicyTranslator.translate(policyJson);
// after
if (policyJson == null || policyJson.trim().isEmpty()) {
  throw new IllegalArgumentException("authorization policy file is empty");
}
List<RBAC> rbacs = AuthorizationPolicyTranslator.translate(policyJson);
Defensive patterns

Strategy: validation

Validate before calling

Object parsed = JsonParser.parse(policyJson);
if (!(parsed instanceof Map)) {
  throw new IllegalArgumentException("policy must be a JSON object, got: " + parsed);
}

Type guard

static boolean isJsonObject(String s) {
  try { return JsonParser.parse(s) instanceof Map; } catch (Exception e) { return false; }
}

Try / catch

try {
  List<RBAC> rbacs = AuthorizationPolicyTranslator.translate(policyJson);
} catch (IllegalArgumentException e) {
  log.error("Invalid authorization policy: " + e.getMessage());
  throw new ConfigException("Bad authz policy", e);
}

Prevention

When it happens

Trigger: Calling AuthorizationPolicyTranslator.translate(policy) with a policy string that parses to null, or to a JSON scalar/array instead of an object — e.g. empty string, whitespace, "null", a bare quoted string, or a JSON array.

Common situations: Config file loaded empty or not interpolated (env var unset leading to literal 'null'), reading a YAML policy that parses to a scalar, truncating the file, or passing the wrong file's contents.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at authz/src/main/java/io/grpc/authz/AuthorizationPolicyTranslator.java:169

          .addAllPrincipals(principals)
          .build();
      policies.put(name + "_" + policyName, policy);
    }
    return policies;
  }

  /** 
   * Translates a gRPC authorization policy in JSON string to Envoy RBAC policies.
   * On success, will return one of the following -
   * 1. One allow RBAC policy or,
   * 2. Two RBAC policies, deny policy followed by allow policy.
   * If the policy cannot be parsed or is invalid, an exception will be thrown.
   */
  public static List<RBAC> translate(String authorizationPolicy) 
            throws IllegalArgumentException, IOException {
    Object jsonObject = JsonParser.parse(authorizationPolicy);
    if (!(jsonObject instanceof Map)) {
      throw new IllegalArgumentException(
          "Authorization policy should be a JSON object. Found: "
          + (jsonObject == null ? null : jsonObject.getClass()));
    }
    @SuppressWarnings("unchecked")
    Map<String, ?> json = (Map<String, ?>)jsonObject;
    String name = JsonUtil.getString(json, "name");
    if (name == null || name.isEmpty()) {
      throw new IllegalArgumentException("\"name\" is absent or empty");
    }
    List<RBAC> rbacs = new ArrayList<>();
    List<Map<String, ?>> objects = JsonUtil.getListOfObjects(json, "deny_rules");
    if (objects != null && !objects.isEmpty()) {
      rbacs.add(
          RBAC.newBuilder()
          .setAction(Action.DENY)
          .putAllPolicies(parseRules(objects, name))
          .build());
    }

View on GitHub (pinned to 64daddc1f3)