{"record":{"id":"bd6be06b9dba7ebb","repo":"apache/iceberg","slug":"cannot-convert-json-to-literal-node","errorCode":null,"errorMessage":"Cannot convert JSON to literal: \" + node","messagePattern":"Cannot convert JSON to literal: \" \\+ node","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java","lineNumber":399,"sourceCode":"          type.equalsIgnoreCase(LITERAL), \"Cannot parse type as a literal: %s\", type);\n      return toValue.apply(JsonUtil.get(VALUE, valueNode));\n    }\n\n    // the node is a directly embedded literal value\n    return toValue.apply(valueNode);\n  }\n\n  private static Object asObject(JsonNode node) {\n    if (node.isIntegralNumber() && node.canConvertToLong()) {\n      return node.asLong();\n    } else if (node.isTextual()) {\n      return node.asText();\n    } else if (node.isFloatingPointNumber()) {\n      return node.asDouble();\n    } else if (node.isBoolean()) {\n      return node.asBoolean();\n    } else {\n      throw new IllegalArgumentException(\"Cannot convert JSON to literal: \" + node);\n    }\n  }\n\n  @SuppressWarnings(\"unchecked\")\n  private static <T> UnboundTerm<T> term(JsonNode node) {\n    if (node.isTextual()) {\n      return Expressions.ref(node.asText());\n    } else if (node.isObject()) {\n      String type = JsonUtil.getString(TYPE, node);\n      switch (type) {\n        case REFERENCE:\n          return Expressions.ref(JsonUtil.getString(TERM, node));\n        case TRANSFORM:\n          UnboundTerm<T> child = term(JsonUtil.get(TERM, node));\n          String transform = JsonUtil.getString(TRANSFORM, node);\n          return (UnboundTerm<T>)\n              Expressions.transform(child.ref().name(), Transforms.fromString(transform));\n        default:","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/expressions/ExpressionParser.java#L381-L417","documentation":"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.","triggerScenarios":"ExpressionParser.fromJson on predicate JSON whose values array contains a literal node of an unsupported shape (nested object/array, null) instead of a scalar.","commonSituations":"Hand-written or tool-generated expression JSON with nested literal values; newer producers emitting literal encodings this parser version does not understand.","solutions":["Ensure predicate literal values in the JSON are plain scalars (string, number, boolean).","Check for object/array-shaped literals and flatten or remove them before parsing.","Upgrade Iceberg if the JSON was produced by a newer writer with extended literal encoding."],"exampleFix":"// before\n// JSON: {\"type\":\"predicate\",\"term\":\"col\",\"op\":\"eq\",\"values\":[{\"nested\":1}]}\nExpression e = ExpressionParser.fromJson(node);\n// after\n// JSON: {\"type\":\"predicate\",\"term\":\"col\",\"op\":\"eq\",\"values\":[1]}\nExpression e = ExpressionParser.fromJson(node);","handlingStrategy":"validation","validationCode":"JsonNode v = valueNode;\nif (!(v.isTextual() || v.isNumber() || v.isBoolean())) {\n  throw new IllegalArgumentException(\"literal must be scalar: \" + v.getNodeType());\n}","typeGuard":"boolean isScalarLiteral(JsonNode n) { return n.isTextual() || n.isNumber() || n.isBoolean(); }","tryCatchPattern":"try {\n  Expression e = ExpressionParser.fromJson(node);\n} catch (IllegalArgumentException e) {\n  throw new IllegalArgumentException(\"malformed predicate literal in expression JSON\", e);\n}","preventionTips":["Emit only scalar literals (string/number/boolean) in predicate values arrays.","Never embed nested objects/arrays as literal values.","Round-trip test: toJson output must parse with fromJson."],"tags":["expressions","json","literals","deserialization"],"backgroundTag":"invalid-argument-format","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}