apache/iceberg · error · IllegalArgumentException

Cannot convert JSON to literal: " + node

Error message

Cannot convert JSON to literal: " + node

What it means

ExpressionParser.asObject converts a JsonNode into a plain Java value (String, Double, Boolean, etc.) for use as a predicate literal. Node shapes it cannot map — objects, arrays, nulls, or other unsupported scalars — trigger this IllegalArgumentException. The JSON literal is not representable as an Iceberg predicate literal value.

Source

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

          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();
    } else if (node.isTextual()) {
      return node.asText();
    } else if (node.isFloatingPointNumber()) {
      return node.asDouble();
    } else if (node.isBoolean()) {
      return node.asBoolean();
    } else {
      throw new IllegalArgumentException("Cannot convert JSON to literal: " + node);
    }
  }

  @SuppressWarnings("unchecked")
  private static <T> UnboundTerm<T> term(JsonNode node) {
    if (node.isTextual()) {
      return Expressions.ref(node.asText());
    } else if (node.isObject()) {
      String type = JsonUtil.getString(TYPE, node);
      switch (type) {
        case REFERENCE:
          return Expressions.ref(JsonUtil.getString(TERM, node));
        case TRANSFORM:
          UnboundTerm<T> child = term(JsonUtil.get(TERM, node));
          String transform = JsonUtil.getString(TRANSFORM, node);
          return (UnboundTerm<T>)
              Expressions.transform(child.ref().name(), Transforms.fromString(transform));
        default:

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure predicate literal values in the JSON are plain scalars (string, number, boolean).
  2. Check for object/array-shaped literals and flatten or remove them before parsing.
  3. Upgrade Iceberg if the JSON was produced by a newer writer with extended literal encoding.

Example fix

// before
// JSON: {"type":"predicate","term":"col","op":"eq","values":[{"nested":1}]}
Expression e = ExpressionParser.fromJson(node);
// after
// JSON: {"type":"predicate","term":"col","op":"eq","values":[1]}
Expression e = ExpressionParser.fromJson(node);
Defensive patterns

Strategy: validation

Validate before calling

JsonNode v = valueNode;
if (!(v.isTextual() || v.isNumber() || v.isBoolean())) {
  throw new IllegalArgumentException("literal must be scalar: " + v.getNodeType());
}

Type guard

boolean isScalarLiteral(JsonNode n) { return n.isTextual() || n.isNumber() || n.isBoolean(); }

Try / catch

try {
  Expression e = ExpressionParser.fromJson(node);
} catch (IllegalArgumentException e) {
  throw new IllegalArgumentException("malformed predicate literal in expression JSON", e);
}

Prevention

When it happens

Trigger: ExpressionParser.fromJson on predicate JSON whose values array contains a literal node of an unsupported shape (nested object/array, null) instead of a scalar.

Common situations: Hand-written or tool-generated expression JSON with nested literal values; newer producers emitting literal encodings this parser version does not understand.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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