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.

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.

Appendix: 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)