{"record":{"id":"8a51f9f421789421","repo":"apache/iceberg","slug":"invalid-primitive-type-for-decimal-primitivetype","errorCode":null,"errorMessage":"Invalid primitive type for decimal: <primitiveType>","messagePattern":"Invalid primitive type for decimal: <primitiveType>","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"parquet/src/main/java/org/apache/iceberg/parquet/ParquetValueReaders.java","lineNumber":119,"sourceCode":"  public static ParquetValueReader<BigDecimal> bigDecimals(ColumnDescriptor desc) {\n    LogicalTypeAnnotation decimal = desc.getPrimitiveType().getLogicalTypeAnnotation();\n    Preconditions.checkArgument(\n        decimal instanceof DecimalLogicalTypeAnnotation,\n        \"Invalid timestamp logical type: \" + decimal);\n\n    int scale = ((DecimalLogicalTypeAnnotation) decimal).getScale();\n\n    switch (desc.getPrimitiveType().getPrimitiveTypeName()) {\n      case FIXED_LEN_BYTE_ARRAY:\n      case BINARY:\n        return new BinaryAsDecimalReader(desc, scale);\n      case INT64:\n        return new LongAsDecimalReader(desc, scale);\n      case INT32:\n        return new IntegerAsDecimalReader(desc, scale);\n    }\n\n    throw new IllegalArgumentException(\n        \"Invalid primitive type for decimal: \" + desc.getPrimitiveType());\n  }\n\n  public static ParquetValueReader<Long> times(ColumnDescriptor desc) {\n    LogicalTypeAnnotation time = desc.getPrimitiveType().getLogicalTypeAnnotation();\n    Preconditions.checkArgument(\n        time instanceof TimeLogicalTypeAnnotation, \"Invalid time logical type: \" + time);\n\n    TimeUnit unit = ((TimeLogicalTypeAnnotation) time).getUnit();\n    if (unit == LogicalTypeAnnotation.TimeUnit.MILLIS) {\n      return new TimeMillisReader(desc);\n    }\n\n    return new UnboxedReader<>(desc);\n  }\n\n  public static ParquetValueReader<Long> timestamps(ColumnDescriptor desc) {\n    if (desc.getPrimitiveType().getPrimitiveTypeName() == PrimitiveType.PrimitiveTypeName.INT96) {","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/parquet/src/main/java/org/apache/iceberg/parquet/ParquetValueReaders.java#L101-L137","documentation":"ParquetValueReaders.bigDecimals builds a decimal reader based on the column's underlying Parquet primitive type. Only FIXED_LEN_BYTE_ARRAY, INT64, and INT32 physical types are valid for decimals; anything else (e.g. BINARY, FLOAT, DOUBLE, INT96) triggers IllegalArgumentException. It reflects a schema mismatch between the Parquet file's declared type and Iceberg's decimal expectation.","triggerScenarios":"Calling ParquetValueReaders.bigDecimals(ColumnDescriptor, int) with a descriptor whose primitive type is not FIXED_LEN_BYTE_ARRAY/INT64/INT32 — typically a file whose decimal column was written with an invalid physical type or whose schema annotation was applied to the wrong physical type.","commonSituations":"Files written by non-Iceberg or buggy writers declaring decimal as BINARY/other; schema evolution or hand-edited Parquet schemas applying DECIMAL logical type to float/double columns; mismatch between expected and actual file schema in a read task.","solutions":["Fix the writer to declare decimals with the correct physical type (FIXED_LEN_BYTE_ARRAY, INT64, or INT32 per precision).","Regenerate or rewrite the offending Parquet files with a correct decimal schema.","Verify the file schema with parquet-tools and ensure the DECIMAL logical type annotation matches the physical type.","If reading third-party data, map the column to a supported type instead of decimal."],"exampleFix":"// before\nTypes.DecimalType.of(10, 2) written as parquet BINARY  // invalid\n// after\n// write with REQUIRED FIXED_LEN_BYTE_ARRAY(16) + DECIMAL(10,2) annotation,\n// or INT64 for precision <= 18","handlingStrategy":"validation","validationCode":"PrimitiveType t = desc.getPrimitiveType();\nif (t.getPrimitiveTypeName() != FIXED_LEN_BYTE_ARRAY\n    && t.getPrimitiveTypeName() != INT64\n    && t.getPrimitiveTypeName() != INT32) {\n  throw new IllegalArgumentException(\"Column cannot be read as decimal: \" + t);\n}","typeGuard":null,"tryCatchPattern":"try {\n  return ParquetValueReaders.bigDecimals(desc, scale);\n} catch (IllegalArgumentException e) {\n  LOG.error(\"Bad physical type for decimal: {}\", desc.getPrimitiveType());\n  throw e;\n}","preventionTips":["Write decimals with FIXED_LEN_BYTE_ARRAY, INT64, or INT32 physical types.","Validate file schemas against the Iceberg schema before reads.","Check logical type annotations match physical types with parquet-tools."],"tags":["parquet","decimal","schema-mismatch","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}