{"record":{"id":"685672924beb862d","repo":"apache/iceberg","slug":"invalid-primitive-type-for-decimal-primitive","errorCode":null,"errorMessage":"Invalid primitive type for decimal: ${primitive}","messagePattern":"Invalid primitive type for decimal: (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"parquet/src/main/java/org/apache/iceberg/parquet/VariantReaderBuilder.java","lineNumber":285,"sourceCode":"    @Override\n    public Optional<VariantValueReader> visit(UUIDLogicalTypeAnnotation logical) {\n      VariantValueReader reader =\n          ParquetVariantReaders.asVariant(PhysicalType.UUID, ParquetValueReaders.uuids(desc));\n      return Optional.of(reader);\n    }\n\n    private static PhysicalType variantDecimalType(PrimitiveType primitive) {\n      switch (primitive.getPrimitiveTypeName()) {\n        case FIXED_LEN_BYTE_ARRAY:\n        case BINARY:\n          return PhysicalType.DECIMAL16;\n        case INT64:\n          return PhysicalType.DECIMAL8;\n        case INT32:\n          return PhysicalType.DECIMAL4;\n      }\n\n      throw new IllegalArgumentException(\"Invalid primitive type for decimal: \" + primitive);\n    }\n  }\n}\n","sourceCodeStart":267,"sourceCodeEnd":289,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/parquet/src/main/java/org/apache/iceberg/parquet/VariantReaderBuilder.java#L267-L289","documentation":"Thrown by VariantReaderBuilder.variantDecimalType() when a shredded decimal typed_value column's physical type is neither INT32 nor INT64 (DECIMAL4/DECIMAL8). Variant decimal shredding only supports INT32- and INT64-backed decimals; FLBA/BINARY-backed wide decimals are rejected.","triggerScenarios":"Reading a shredded Variant decimal whose typed_value physical primitive is not INT32/INT64 (e.g. FIXED_LEN_BYTE_ARRAY or BINARY decimal) via primitive() -> variantDecimalType.","commonSituations":"Writers shredding high-precision decimals (precision > 18) which require FLBA/BINARY backing; tooling defaulting decimals to fixed-length byte arrays; cross-system schemas where decimal backing differs.","solutions":["Rewrite the shredded decimal so it is backed by INT32 (precision <= 9) or INT64 (precision <= 18).","Keep high-precision values unshredded inside the Variant binary instead of a typed decimal column.","Change the producing writer to select an INT32/INT64-backed decimal when shredding."],"exampleFix":"// before\nTypes.required(PrimitiveTypeName.FIXED_LEN_BYTE_ARRAY).length(16).as(DecimalLogicalType.decimalType(38, 10)).named(\"typed_value\")\n\n// after (precision within 18)\nTypes.required(PrimitiveTypeName.INT64).as(DecimalLogicalType.decimalType(18, 10)).named(\"typed_value\")","handlingStrategy":"validation","validationCode":"PrimitiveTypeName p = typedValue.getType().asPrimitiveType().getPrimitiveTypeName();\nPreconditions.checkArgument(p == INT32 || p == INT64,\n    \"Shredded decimals must be INT32/INT64-backed, got %s\", p);","typeGuard":"boolean isShreddableDecimal(Type t) {\n  if (!t.isPrimitive()) return false;\n  PrimitiveTypeName p = t.asPrimitiveType().getPrimitiveTypeName();\n  return p == PrimitiveTypeName.INT32 || p == PrimitiveTypeName.INT64;\n}","tryCatchPattern":"try {\n  openVariantReader(schema);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Invalid primitive type for decimal\")) {\n    readUnshreddedVariant(column); // wide decimals stay in variant binary\n  } else throw e;\n}","preventionTips":["Only shred decimals whose precision fits INT32 (<=9) or INT64 (<=18)","Keep decimal(>18) values unshredded inside the Variant payload","Check the physical backing type, not just the decimal logical annotation"],"tags":["parquet","variant","decimal","shredding"],"backgroundTag":"unsupported-operation","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"}