{"record":{"id":"be90ac93614ebef4","repo":"apache/iceberg","slug":"invalid-field-id-for-content-stats-s","errorCode":null,"errorMessage":"Invalid field ID for content stats: %s","messagePattern":"Invalid field ID for content stats: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/ContentFileParser.java","lineNumber":354,"sourceCode":"      Preconditions.checkArgument(\n          fieldStats != null && fieldStats.isObject(),\n          \"Cannot parse content stats for field %s from non-object: %s\",\n          fieldId,\n          fieldStats);\n      Integer avgValueSize = JsonUtil.getIntOrNull(AVG_VALUE_SIZE_IN_BYTES, fieldStats);\n      if (avgValueSize != null) {\n        avgValueSizes.put(parseFieldId(fieldId), avgValueSize);\n      }\n    }\n\n    return avgValueSizes.isEmpty() ? null : avgValueSizes;\n  }\n\n  private static int parseFieldId(String fieldId) {\n    try {\n      return Integer.parseInt(fieldId);\n    } catch (NumberFormatException e) {\n      throw new IllegalArgumentException(\n          String.format(\"Invalid field ID for content stats: %s\", fieldId), e);\n    }\n  }\n\n  private static void partitionToJson(\n      Types.StructType partitionType, StructLike partitionData, JsonGenerator generator)\n      throws IOException {\n    generator.writeStartArray();\n    List<Types.NestedField> fields = partitionType.fields();\n    for (int pos = 0; pos < fields.size(); ++pos) {\n      Types.NestedField field = fields.get(pos);\n      Object partitionValue = partitionData.get(pos, Object.class);\n      SingleValueParser.toJson(field.type(), partitionValue, generator);\n    }\n    generator.writeEndArray();\n  }\n\n  private static PartitionData partitionFromJson(","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/ContentFileParser.java#L336-L372","documentation":"ContentFileParser.fromJson parses content-stats field IDs from JSON where keys are numeric field ID strings. parseFieldId converts each key to an int; a non-numeric key means the JSON is malformed for this format, so an IllegalArgumentException with the offending string is thrown.","triggerScenarios":"Calling ContentFileParser.fromJson (for content stats / avg value sizes) on JSON whose field-ID keys are not numeric strings, e.g. column names instead of IDs.","commonSituations":"Hand-written or third-party-produced stats JSON using column names as keys; mixing specs/versions that serialize stats differently; copy-paste edits of stats JSON.","solutions":["Fix the JSON so keys are integer field ID strings.","Regenerate the stats content with the same Iceberg version's writer.","Verify which producer wrote the JSON and align its key format with the Iceberg content-stats spec."],"exampleFix":"// before\n{\"row_count\": 100, \"column_sizes\": {\"id\": 16}}\n// after\n{\"row_count\": 100, \"column_sizes\": {\"1\": 16}}","handlingStrategy":"validation","validationCode":"boolean allNumeric = jsonObject.keySet().stream().allMatch(k -> k.matches(\"\\\\d+\"));\nif (!allNumeric) throw new IllegalArgumentException(\"stats keys must be field IDs\");","typeGuard":null,"tryCatchPattern":"try { ContentFileParser.fromJson(...); } catch (IllegalArgumentException e) {\n  LOG.error(\"bad field ID: {}\", e.getMessage());\n  throw e;\n}","preventionTips":["Always serialize stats with ContentFileParser.toJson.","Use field IDs, never column names, as JSON keys.","Pin producer/consumer to the same Iceberg version."],"tags":["json","parsing","field-id"],"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"}