apache/iceberg · error · IllegalArgumentException

Cannot convert update requirement to json. Unrecognized type

Error message

Cannot convert update requirement to json. Unrecognized type: %s

What it means

Thrown by UpdateRequirementParser.toJson when it encounters an UpdateRequirement whose RequirementType is not one of the known cases in its switch. The parser only knows the requirement types defined at its time of compilation; a newer requirement type from a newer Iceberg version (or a custom implementation) cannot be serialized, so it fails fast with IllegalArgumentException rather than writing an incomplete requirement.

Source

Thrown at core/src/main/java/org/apache/iceberg/UpdateRequirementParser.java:134

        break;
      case ASSERT_LAST_ASSIGNED_PARTITION_ID:
        writeAssertLastAssignedPartitionId(
            (UpdateRequirement.AssertLastAssignedPartitionId) updateRequirement, generator);
        break;
      case ASSERT_CURRENT_SCHEMA_ID:
        writeAssertCurrentSchemaId(
            (UpdateRequirement.AssertCurrentSchemaID) updateRequirement, generator);
        break;
      case ASSERT_DEFAULT_SPEC_ID:
        writeAssertDefaultSpecId(
            (UpdateRequirement.AssertDefaultSpecID) updateRequirement, generator);
        break;
      case ASSERT_DEFAULT_SORT_ORDER_ID:
        writeAssertDefaultSortOrderId(
            (UpdateRequirement.AssertDefaultSortOrderID) updateRequirement, generator);
        break;
      default:
        throw new IllegalArgumentException(
            String.format(
                "Cannot convert update requirement to json. Unrecognized type: %s",
                requirementType));
    }

    generator.writeEndObject();
  }

  /**
   * Read MetadataUpdate from a JSON string.
   *
   * @param json a JSON string of a MetadataUpdate
   * @return a MetadataUpdate object
   */
  public static UpdateRequirement fromJson(String json) {
    return JsonUtil.parse(json, UpdateRequirementParser::fromJson);
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Align all Iceberg jars to one version so the parser knows every requirement type in use (check for mixed iceberg-core versions on the classpath).
  2. Check for duplicate/shaded org.apache.iceberg classes (mvn dependency:tree, ensure a single iceberg-core) that cause version skew between parser and requirement classes.
  3. Upgrade iceberg-core on the component performing serialization if a newer requirement type must be supported.
  4. Do not pass custom/unknown UpdateRequirement implementations to the standard parser; extend the parser in a fork only if truly needed.

Example fix

// before (mixed versions: parser predates ASSERT_REF_SNAPSHOT_ID)
String json = UpdateRequirementParser.toJson(requirement); // throws
// after: pin one Iceberg version across app and runtime
// build.gradle: implementation 'org.apache.iceberg:iceberg-core:1.6.1' everywhere
// (no iceberg-core 1.4 jars left on the classpath)
Defensive patterns

Strategy: validation

Validate before calling

switch (requirement.type()) {
  case ASSERT_TABLE_UUID: case ASSERT_LAST_ASSIGNED_FIELD_ID:
  case ASSERT_CURRENT_SCHEMA_ID: case ASSERT_LAST_ASSIGNED_PARTITION_ID:
  case ASSERT_DEFAULT_SPEC_ID: case ASSERT_DEFAULT_SORT_ORDER_ID:
  case ASSERT_REF_SNAPSHOT_ID: break;
  default: throw new IllegalStateException("Requirement not serializable by this Iceberg version: " + requirement.type());
}

Type guard

boolean serializable(UpdateRequirement r) {
  return EnumSet.of(RequirementType.ASSERT_TABLE_UUID, RequirementType.ASSERT_LAST_ASSIGNED_FIELD_ID,
      RequirementType.ASSERT_CURRENT_SCHEMA_ID, RequirementType.ASSERT_LAST_ASSIGNED_PARTITION_ID,
      RequirementType.ASSERT_DEFAULT_SPEC_ID, RequirementType.ASSERT_DEFAULT_SORT_ORDER_ID,
      RequirementType.ASSERT_REF_SNAPSHOT_ID).contains(r.type());
}

Try / catch

try {
  String json = UpdateRequirementParser.toJson(requirement);
} catch (IllegalArgumentException e) {
  if (e.getMessage().contains("Unrecognized type")) {
    throw new IllegalStateException("Iceberg version skew: upgrade iceberg-core to match requirement type", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling UpdateRequirementParser.toJson (directly or via REST catalog client metadata-update serialization) on an UpdateRequirement whose type() is not in {ASSERT_TABLE_UUID, ASSERT_LAST_ASSIGNED_FIELD_ID, ASSERT_CURRENT_SCHEMA_ID, ASSERT_LAST_ASSIGNED_PARTITION_ID, ASSERT_DEFAULT_SPEC_ID, ASSERT_DEFAULT_SORT_ORDER_ID, ASSERT_REF_SNAPSHOT_ID}.

Common situations: Mixing Iceberg jar versions — an app built against a newer Iceberg with a new requirement type submits work to a runtime with an older core jar; custom UpdateRequirement implementations passed into the parser; shaded/duplicated iceberg-core classes on the classpath where the parser is older than the requirement classes.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/ea498694a85f5fd2. Report an issue: GitHub.