apache/iceberg · error · UnsupportedOperationException

Unsupported operation: " + op

Error message

Unsupported operation: " + op

What it means

While deserializing a predicate from JSON, ExpressionParser maps the JSON "op" string to an Expression.Operation; if the operation string is not one the parser recognizes (outside the supported set in its switch), it throws UnsupportedOperationException. This means the JSON was produced by a newer Iceberg version or hand-edited with an invalid op value.

Source

Thrown at core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java:373

        T value = literal(JsonUtil.get(VALUE, node), convertValue);
        return Expressions.predicate(op, term, ImmutableList.of(value));
      case IN:
      case NOT_IN:
        // literal set predicates
        Preconditions.checkArgument(
            node.has(VALUES), "Cannot parse %s predicate: missing values", op);
        Preconditions.checkArgument(
            !node.has(VALUE), "Cannot parse %s predicate: has invalid value field", op);
        JsonNode valuesNode = JsonUtil.get(VALUES, node);
        Preconditions.checkArgument(
            valuesNode.isArray(), "Cannot parse literals from non-array: %s", valuesNode);
        return Expressions.predicate(
            op,
            term,
            Iterables.transform(
                ((ArrayNode) valuesNode)::elements, valueNode -> literal(valueNode, convertValue)));
      default:
        throw new UnsupportedOperationException("Unsupported operation: " + op);
    }
  }

  private static <T> T literal(JsonNode valueNode, Function<JsonNode, T> toValue) {
    if (valueNode.isObject() && valueNode.has(TYPE)) {
      String type = JsonUtil.getString(TYPE, valueNode);
      Preconditions.checkArgument(
          type.equalsIgnoreCase(LITERAL), "Cannot parse type as a literal: %s", type);
      return toValue.apply(JsonUtil.get(VALUE, valueNode));
    }

    // the node is a directly embedded literal value
    return toValue.apply(valueNode);
  }

  private static Object asObject(JsonNode node) {
    if (node.isIntegralNumber() && node.canConvertToLong()) {
      return node.asLong();

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Upgrade the Iceberg library to a version that supports the operation string in the JSON.
  2. Validate the op string against Expression.Operation names before parsing.
  3. Regenerate the JSON from a supported Iceberg version rather than hand-editing.

Example fix

// before
Expression parsed = ExpressionParser.fromJson(JsonUtil.parseJson(json));
// after
String op = JsonUtil.getString("op", predNode);
if (!isKnownOperation(op)) {
  throw new IllegalArgumentException("unsupported op in expression JSON: " + op);
}
Expression parsed = ExpressionParser.fromJson(JsonUtil.parseJson(json));
Defensive patterns

Strategy: validation

Validate before calling

String op = JsonUtil.getString("op", predNode);
if (Stream.of(Expression.Operation.values()).noneMatch(o -> o.toString().equals(op))) {
  throw new IllegalArgumentException("unknown predicate op: " + op);
}

Try / catch

try {
  Expression e = ExpressionParser.fromJson(node);
} catch (UnsupportedOperationException e) {
  LOG.error("unsupported op in expression JSON (library upgrade needed?)", e);
  throw e;
}

Prevention

When it happens

Trigger: ExpressionParser.fromJson on JSON whose predicate operation string is not a known Expression.Operation name — forward-compatibility gap or manual JSON editing.

Common situations: Reading expression JSON written by a newer Iceberg release that added operations; corrupted or hand-written metadata files.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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