grpc/grpc-java · error · ClassCastException

value '%s' for key '%s' in '%s' is not object

Error message

value '%s' for key '%s' in '%s' is not object

What it means

JsonUtil.getObject retrieves a key from a parsed JSON object and requires the value to be a JSON object (Map). If the key exists with any other type, it throws ClassCastException('value ... is not object'), embedding the offending value, key, and parent object in the message.

Source

Thrown at core/src/main/java/io/grpc/internal/JsonUtil.java:92

      return null;
    }
    return checkStringList(list);
  }

  /**
   * Gets an object from an object for the given key.  If the key is not present, this returns null.
   * If the value is not a Map, throws an exception.
   */
  @SuppressWarnings("unchecked")
  @Nullable
  public static Map<String, ?> getObject(Map<String, ?> obj, String key) {
    assert key != null;
    if (!obj.containsKey(key)) {
      return null;
    }
    Object value = obj.get(key);
    if (!(value instanceof Map)) {
      throw new ClassCastException(
          String.format("value '%s' for key '%s' in '%s' is not object", value, key, obj));
    }
    return (Map<String, ?>) value;
  }

  /**
   * Gets a number from an object for the given key.  If the key is not present, this returns null.
   * If the value does not represent a double, throws an exception.
   */
  @Nullable
  public static Double getNumberAsDouble(Map<String, ?> obj, String key) {
    assert key != null;
    if (!obj.containsKey(key)) {
      return null;
    }
    Object value = obj.get(key);
    if (value instanceof Double) {
      return (Double) value;

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Fix the JSON so the key maps to an object: "key": {...} not "key": "..."
  2. Validate bootstrap/service-config JSON against the gRPC schema before startup
  3. Open the file named indirectly by the message and re-check the nesting of that key
  4. Regenerate the config with the tooling's current version to eliminate stale shapes

Example fix

// before
{"xds_server": "trafficdirector.googleapis.com"}
// after
{"xds_server": {"server_uri": "trafficdirector.googleapis.com", "channel_creds": [...]}}
Defensive patterns

Strategy: validation

Validate before calling

Object v = cfg.get("node");
if (v != null && !(v instanceof Map)) throw new IllegalArgumentException("node must be a JSON object");

Type guard

@SuppressWarnings("unchecked")
Map<String,?> asObject(Object v) { return v instanceof Map ? (Map<String,?>) v : null; }

Try / catch

try { JsonUtil.getObject(bootstrap, "node"); }
catch (ClassCastException e) { log.error("bad xDS bootstrap: {}", e.getMessage()); throw new InvalidConfigException(e); }

Prevention

When it happens

Trigger: Calling getObject/getList-of-objects on a JSON config where the key holds a scalar or array instead of a nested object — e.g. xDS bootstrap 'node' or 'xds_server' written as a string, or a nested section accidentally flattened.

Common situations: Hand-written gRPC service config / xDS bootstrap files with wrong nesting; version drift where a field changed from object to scalar between config generators; copy-paste errors merging JSON sections.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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