apache/hadoop · error · IllegalArgumentException

Cannot serialize field

Error message

Cannot serialize field {} into JSON

What it means

RBFMetrics.getJson() serializes a BaseRecord (e.g. RouterState, MountTable, MembershipState) into a JSONObject for JMX output by reflectively reading every declared field. If reading any field via getField(record, fieldName) throws (inaccessible field, incompatible type in the record, or a nested value that fails conversion), it rethrows IllegalArgumentException('Cannot serialize field <name> into JSON'). The original exception is deliberately swallowed, so the field name in the message is your only clue.

Solutions

  1. Identify the failing field from the message and inspect that field's type in the corresponding BaseRecord class
  2. If the field is a custom type, implement/verify its serialization support (make it a BaseRecord, String-primitive, or add a getter the serializer uses)
  3. Check for state-store schema/version drift after upgrade: refresh records (e.g. re-register Router/NN heartbeats) so new-format records replace old ones
  4. As a maintainer, chain the cause: throw new IllegalArgumentException(msg, e) to expose the root reason

Example fix

// before
} catch (Exception e) {
  throw new IllegalArgumentException(
      "Cannot serialize field " + fieldName + " into JSON");
}

// after (preserves root cause)
} catch (Exception e) {
  throw new IllegalArgumentException(
      "Cannot serialize field " + fieldName + " into JSON", e);
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  String json = routerMetrics.getNamenodeRegistrations(); // any record-dumping JMX attr
} catch (IllegalArgumentException e) {
  if (e.getMessage() != null && e.getMessage().startsWith("Cannot serialize field")) {
    // extract field name, inspect that BaseRecord field's type; likely schema drift or custom type
    LOG.warn("JMX record serialization failed: {}", e.getMessage());
  } else { throw e; }
}

Prevention

When it happens

Trigger: JMX queries on RBFMetrics that dump state-store records, e.g. getRouters(), getMountTable(), getNameservices(), getNamenodeRegistrations() returning records whose fields include enums/Date/nested BaseRecords the reflective reader cannot handle; a custom BaseRecord subclass registered in the state store whose field types break getField(); accessing a field on a partially-updated record.

Common situations: Scraping RBF JMX beans with monitoring after adding a custom record type or after a Hadoop version change altered record schemas; records loaded from an older state-store driver (serialization version mismatch); reflective access blocked under stricter JRE module rules.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/6d31c0af01e411bb. Report an issue: GitHub.

Appendix: source

Thrown at hadoop-hdfs-project/hadoop-hdfs-rbf/src/main/java/org/apache/hadoop/hdfs/server/federation/metrics/RBFMetrics.java:1004

   *
   * @return Map representing the data for the JSON representation.
   */
  private static Map<String, Object> getJson(BaseRecord record) {
    Map<String, Object> json = new HashMap<>();
    Map<String, Class<?>> fields = getFields(record);

    for (String fieldName : fields.keySet()) {
      if (!fieldName.equalsIgnoreCase("proto")) {
        try {
          Object value = getField(record, fieldName);
          if (value instanceof BaseRecord) {
            BaseRecord recordField = (BaseRecord) value;
            json.putAll(getJson(recordField));
          } else {
            json.put(fieldName, value == null ? JSONObject.NULL : value);
          }
        } catch (Exception e) {
          throw new IllegalArgumentException(
              "Cannot serialize field " + fieldName + " into JSON");
        }
      }
    }
    return json;
  }

  /**
   * Returns all serializable fields in the object.
   *
   * @return Map with the fields.
   */
  private static Map<String, Class<?>> getFields(BaseRecord record) {
    Map<String, Class<?>> getters = new HashMap<>();
    for (Method m : record.getClass().getDeclaredMethods()) {
      if (m.getName().startsWith("get")) {
        try {
          Class<?> type = m.getReturnType();

View on GitHub (pinned to 2add963021)