{"record":{"id":"c28b190bd7fc70d4","repo":"apache/iceberg","slug":"cannot-coerce-value-to-int","errorCode":null,"errorMessage":"Cannot coerce value to int: ","messagePattern":"Cannot coerce value to int: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/avro/AvroSchemaUtil.java","lineNumber":432,"sourceCode":"        return mappedField.id();\n      }\n    }\n\n    return null;\n  }\n\n  public static boolean hasFieldId(Schema.Field field) {\n    return field.getObjectProp(FIELD_ID_PROP) != null;\n  }\n\n  private static int toInt(Object value) {\n    if (value instanceof Number) {\n      return ((Number) value).intValue();\n    } else if (value instanceof String) {\n      return Integer.parseInt((String) value);\n    }\n\n    throw new UnsupportedOperationException(\"Cannot coerce value to int: \" + value);\n  }\n\n  static Schema copyRecord(Schema record, List<Schema.Field> newFields, String newName) {\n    Schema copy;\n    if (newName != null) {\n      copy = Schema.createRecord(newName, record.getDoc(), null, record.isError(), newFields);\n      // the namespace is defaulted to the record's namespace if it is null, which causes renames\n      // without the namespace to fail. using \"\" instead of null changes this behavior to match the\n      // original schema.\n      copy.addAlias(record.getName(), record.getNamespace() == null ? \"\" : record.getNamespace());\n    } else {\n      copy =\n          Schema.createRecord(\n              record.getName(),\n              record.getDoc(),\n              record.getNamespace(),\n              record.isError(),\n              newFields);","sourceCodeStart":414,"sourceCodeEnd":450,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/avro/AvroSchemaUtil.java#L414-L450","documentation":"AvroSchemaUtil.toInt converts an Avro property value (typically a field-id stored in the 'field-id' custom property) into an int. It accepts Numbers and numeric Strings; any other object type cannot be coerced and triggers an UnsupportedOperationException naming the offending value.","triggerScenarios":"Reading field IDs from an Avro schema whose 'field-id' property was written as a non-numeric type (Boolean, Map, List) or is missing its numeric value; calling getId/keyId/valueId/elementId/getFieldId on a schema produced by a foreign Avro writer that does not follow Iceberg's field-id convention.","commonSituations":"Files written by third-party Avro tools that copy Iceberg schema properties incorrectly; hand-edited Avro schemas; schemas round-tripped through systems that re-serialize custom props as JSON objects/booleans.","solutions":["Fix the writer to emit 'field-id' as a numeric value or numeric string (standard Iceberg Avro type conversion)","Pre-process/repair the Avro schema: set the correct integer field-id before reading","If reading third-party files, remap them with a custom reader instead of relying on Iceberg field IDs","Log and inspect the offending value type to identify the writer that produced it"],"exampleFix":"// before: prop written as non-numeric\nschema.addProp(\"field-id\", true);\n// after: numeric value (or numeric string)\nschema.addProp(\"field-id\", 42);\n// or as string that parses\nschema.addProp(\"field-id\", String.valueOf(42));","handlingStrategy":"type-guard","validationCode":"Object v = schema.getObjectProp(\"field-id\");\nif (!(v instanceof Number) && !(v instanceof String)) {\n  throw new IllegalStateException(\"Bad field-id property: \" + v);\n}\nif (v instanceof String && !((String) v).chars().allMatch(Character::isDigit)) {\n  throw new IllegalStateException(\"Non-numeric field-id: \" + v);\n}","typeGuard":"boolean isCoercibleToInt(Object v) {\n  return v instanceof Number || (v instanceof String && ((String) v).matches(\"-?\\\\d+\"));\n}","tryCatchPattern":"try {\n  int id = AvroSchemaUtil.getId(field);\n} catch (UnsupportedOperationException e) {\n  LOG.warn(\"Unreadable field-id on {}\", field.fullName());\n  id = NO_ID;\n}","preventionTips":["Always write Iceberg schemas via the standard AvroSchemaUtil conversion path","Round-trip test schemas through your writer to confirm field-id types survive","Reject third-party writers that mangle custom properties","Log schema properties when field-id lookups fail to aid diagnosis"],"tags":["avro","schema","field-id","type-coercion"],"backgroundTag":"type-mismatch","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"}