This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new eee4a82b4 refactor(types)!: return errors from fixed and decimal 
constructors (#2331)
eee4a82b4 is described below

commit eee4a82b43da0989f1101c8f0132119974406543
Author: Minh Vu <[email protected]>
AuthorDate: Mon Oct 26 21:04:42 2026 +0100

    refactor(types)!: return errors from fixed and decimal constructors (#2331)
    
    Signed-off-by: Minh Vu <[email protected]>
    Co-authored-by: Matt Topol <[email protected]>
---
 bound_set_literal_view_test.go                     |   4 +-
 catalog/glue/schema_test.go                        |   8 +-
 catalog/hive/hive_test.go                          |   4 +-
 catalog/rest/scan_planning_parity_test.go          |   4 +-
 catalog/rest/scan_task_decoder_test.go             |  16 +-
 data_file_codec_bench_test.go                      |   2 +-
 data_file_codec_fingerprint_test.go                |  24 +--
 data_file_codec_test.go                            |   6 +-
 expr_json_test.go                                  |   4 +-
 exprs_test.go                                      |  14 +-
 literals_test.go                                   | 174 ++++++++++-----------
 manifest_partition_bench_test.go                   |   6 +-
 manifest_test.go                                   |  10 +-
 partitions_test.go                                 |   4 +-
 schema_compatibility_test.go                       |  18 +--
 table/arrow_filter_plan_key_test.go                |  10 +-
 table/arrow_filter_plan_test.go                    |  10 +-
 table/arrow_scanner_bench_test.go                  |   4 +-
 table/arrow_utils.go                               |   4 +-
 table/arrow_utils_test.go                          |  14 +-
 table/equality_delete_index_metrics_test.go        |  12 +-
 table/equality_delete_writer_test.go               |   4 +-
 table/evaluators_invalid_bounds_test.go            |   2 +-
 table/evaluators_row_group_test.go                 |   4 +-
 table/in_predicate_extrema_bench_test.go           |   8 +-
 table/in_predicate_extrema_test.go                 |  12 +-
 table/inspect_internal_test.go                     |   6 +-
 table/inspect_partition_append_test.go             |   6 +-
 table/internal/parquet_files_test.go               |  24 +--
 table/internal/utils_test.go                       |   2 +-
 table/internal/variant_bounds.go                   |   7 +-
 table/internal/variant_bounds_test.go              |  26 +++
 table/metadata_internal_test.go                    |   2 +-
 table/partition_residual_test.go                   |   2 +-
 table/partitioned_fanout_writer_review_test.go     |   4 +-
 table/partitioned_fanout_writer_test.go            |  14 +-
 table/scanner_internal_test.go                     |   2 +-
 table/substrait/substrait_decimal_internal_test.go |   4 +-
 table/substrait/substrait_test.go                  |   4 +-
 table/table_test.go                                |   8 +-
 table/transaction_test.go                          |   8 +-
 table/update_schema_test.go                        |  16 +-
 table/variant_residual_fastpath_test.go            |   4 +-
 table/variant_residual_test.go                     |   4 +-
 table/variant_shredded_write_test.go               |   8 +-
 transforms_decimal_bench_test.go                   |   4 +-
 transforms_test.go                                 |  28 ++--
 types.go                                           |  36 ++++-
 types_test.go                                      |  93 +++++++----
 variant_cast_test.go                               |  10 +-
 variant_extract_test.go                            |   2 +-
 visitors_test.go                                   |  10 +-
 website/src/releases.md                            |   1 +
 53 files changed, 402 insertions(+), 315 deletions(-)

diff --git a/bound_set_literal_view_test.go b/bound_set_literal_view_test.go
index 2ee7fe00c..7c9bfb874 100644
--- a/bound_set_literal_view_test.go
+++ b/bound_set_literal_view_test.go
@@ -44,8 +44,8 @@ func TestBoundSetPredicateLiteralsCloneMutableMembers(t 
*testing.T) {
        }{
                {name: "binary_in", typ: iceberg.PrimitiveTypes.Binary, op: 
iceberg.OpIn},
                {name: "binary_not_in", typ: iceberg.PrimitiveTypes.Binary, op: 
iceberg.OpNotIn},
-               {name: "fixed_in", typ: iceberg.FixedTypeOf(16), op: 
iceberg.OpIn},
-               {name: "fixed_not_in", typ: iceberg.FixedTypeOf(16), op: 
iceberg.OpNotIn},
+               {name: "fixed_in", typ: iceberg.MustFixedTypeOf(16), op: 
iceberg.OpIn},
+               {name: "fixed_not_in", typ: iceberg.MustFixedTypeOf(16), op: 
iceberg.OpNotIn},
                {name: "geometry_in", typ: geometry, op: iceberg.OpIn},
                {name: "geometry_not_in", typ: geometry, op: iceberg.OpNotIn},
                {name: "geography_in", typ: geography, op: iceberg.OpIn},
diff --git a/catalog/glue/schema_test.go b/catalog/glue/schema_test.go
index cdc9cf1bf..71e0a1991 100644
--- a/catalog/glue/schema_test.go
+++ b/catalog/glue/schema_test.go
@@ -96,19 +96,19 @@ func TestIcebergTypeToGlueType(t *testing.T) {
                },
                {
                        name:     "decimal type",
-                       input:    iceberg.DecimalTypeOf(10, 2),
+                       input:    iceberg.MustDecimalTypeOf(10, 2),
                        expected: "decimal(10,2)",
                },
                {
                        name:     "fixed type",
-                       input:    iceberg.FixedTypeOf(16),
+                       input:    iceberg.MustFixedTypeOf(16),
                        expected: "binary",
                },
                {
                        name: "nested fixed type",
                        input: &iceberg.ListType{
                                ElementID:       1,
-                               Element:         iceberg.FixedTypeOf(16),
+                               Element:         iceberg.MustFixedTypeOf(16),
                                ElementRequired: true,
                        },
                        expected: "array<binary>",
@@ -153,7 +153,7 @@ func TestFieldToGlueColumn(t *testing.T) {
                        field: iceberg.NestedField{
                                ID:       2,
                                Name:     "price",
-                               Type:     iceberg.DecimalTypeOf(10, 2),
+                               Type:     iceberg.MustDecimalTypeOf(10, 2),
                                Required: false,
                                Doc:      "Price with 2 decimal places",
                        },
diff --git a/catalog/hive/hive_test.go b/catalog/hive/hive_test.go
index 221413fc5..9190b7571 100644
--- a/catalog/hive/hive_test.go
+++ b/catalog/hive/hive_test.go
@@ -1780,8 +1780,8 @@ func TestIcebergTypeToHiveType(t *testing.T) {
                {"string", iceberg.PrimitiveTypes.String, "string"},
                {"uuid", iceberg.PrimitiveTypes.UUID, "string"},
                {"binary", iceberg.PrimitiveTypes.Binary, "binary"},
-               {"decimal", iceberg.DecimalTypeOf(10, 2), "decimal(10,2)"},
-               {"fixed", iceberg.FixedTypeOf(16), "binary(16)"},
+               {"decimal", iceberg.MustDecimalTypeOf(10, 2), "decimal(10,2)"},
+               {"fixed", iceberg.MustFixedTypeOf(16), "binary(16)"},
        }
 
        for _, tt := range tests {
diff --git a/catalog/rest/scan_planning_parity_test.go 
b/catalog/rest/scan_planning_parity_test.go
index 13281c388..5434bb922 100644
--- a/catalog/rest/scan_planning_parity_test.go
+++ b/catalog/rest/scan_planning_parity_test.go
@@ -163,14 +163,14 @@ func newPlanningParityTable(t *testing.T) 
(table.Metadata, *iceio.MemFS) {
        schema := iceberg.NewSchema(0,
                iceberg.NestedField{ID: 1, Name: "tenant", Type: 
iceberg.PrimitiveTypes.Int32},
                iceberg.NestedField{ID: 2, Name: "value", Type: 
iceberg.PrimitiveTypes.Int32},
-               iceberg.NestedField{ID: 3, Name: "amount", Type: 
iceberg.DecimalTypeOf(12, 2)},
+               iceberg.NestedField{ID: 3, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(12, 2)},
                iceberg.NestedField{ID: 4, Name: "ts", Type: 
iceberg.PrimitiveTypes.Timestamp},
                iceberg.NestedField{ID: 5, Name: "tstz", Type: 
iceberg.PrimitiveTypes.TimestampTz},
                iceberg.NestedField{ID: 6, Name: "day", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 7, Name: "clock", Type: 
iceberg.PrimitiveTypes.Time},
                iceberg.NestedField{ID: 8, Name: "uuid", Type: 
iceberg.PrimitiveTypes.UUID},
                iceberg.NestedField{ID: 9, Name: "blob", Type: 
iceberg.PrimitiveTypes.Binary},
-               iceberg.NestedField{ID: 10, Name: "fixed", Type: 
iceberg.FixedTypeOf(3)},
+               iceberg.NestedField{ID: 10, Name: "fixed", Type: 
iceberg.MustFixedTypeOf(3)},
                iceberg.NestedField{ID: 11, Name: "nested", Type: 
&iceberg.StructType{FieldList: []iceberg.NestedField{
                        {ID: 16, Name: "text", Type: 
iceberg.PrimitiveTypes.String},
                }}},
diff --git a/catalog/rest/scan_task_decoder_test.go 
b/catalog/rest/scan_task_decoder_test.go
index 1ad68e576..d87b2066f 100644
--- a/catalog/rest/scan_task_decoder_test.go
+++ b/catalog/rest/scan_task_decoder_test.go
@@ -366,7 +366,7 @@ func TestRESTValueMapUsesIcebergBinaryEncoding(t 
*testing.T) {
        decoded, err := decodeValueMap("lower-bounds", &bounds)
        require.NoError(t, err)
 
-       decimalType := iceberg.DecimalTypeOf(9, 2)
+       decimalType := iceberg.MustDecimalTypeOf(9, 2)
        tests := []struct {
                name    string
                fieldID int
@@ -605,8 +605,8 @@ func TestDecodeScanTasksRejectsDeleteFilesWithoutTasks(t 
*testing.T) {
 func TestDecodePartitionLiteralCoversPrimitiveWireTypes(t *testing.T) {
        t.Parallel()
 
-       decimalType := iceberg.DecimalTypeOf(9, 2)
-       fixedType := iceberg.FixedTypeOf(4)
+       decimalType := iceberg.MustDecimalTypeOf(9, 2)
+       fixedType := iceberg.MustFixedTypeOf(4)
        tests := []struct {
                name        string
                raw         string
@@ -662,7 +662,7 @@ func TestDecodePartitionLiteralRejectsInvalidValues(t 
*testing.T) {
                {"null", `null`, iceberg.PrimitiveTypes.Int64, "null is not 
valid"},
                {"int32 overflow", `2147483648`, iceberg.PrimitiveTypes.Int32, 
"outside int32 range"},
                {"long fraction", `1.5`, iceberg.PrimitiveTypes.Int64, "invalid 
integer value"},
-               {"wrong fixed width", `"00FF"`, iceberg.FixedTypeOf(4), 
"different length"},
+               {"wrong fixed width", `"00FF"`, iceberg.MustFixedTypeOf(4), 
"different length"},
                {"invalid binary hex", `"XYZ"`, iceberg.PrimitiveTypes.Binary, 
"hexadecimal"},
                {"nested value", `{"x":1}`, iceberg.PrimitiveTypes.String, 
"invalid string value"},
        } {
@@ -806,8 +806,8 @@ func newScanTaskDecoderMetadata() *scanTaskDecoderMetadata {
                iceberg.NestedField{ID: 1, Name: "id", Type: 
iceberg.PrimitiveTypes.Int64, Required: true},
                iceberg.NestedField{ID: 2, Name: "category", Type: 
iceberg.PrimitiveTypes.String},
                iceberg.NestedField{ID: 3, Name: "event_date", Type: 
iceberg.PrimitiveTypes.Date},
-               iceberg.NestedField{ID: 4, Name: "amount", Type: 
iceberg.DecimalTypeOf(9, 2)},
-               iceberg.NestedField{ID: 5, Name: "code", Type: 
iceberg.FixedTypeOf(4)},
+               iceberg.NestedField{ID: 4, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 5, Name: "code", Type: 
iceberg.MustFixedTypeOf(4)},
                iceberg.NestedField{ID: 6, Name: "event_time", Type: 
iceberg.PrimitiveTypes.TimestampTzNs},
                iceberg.NestedField{ID: 7, Name: "score", Type: 
iceberg.PrimitiveTypes.Float64},
                iceberg.NestedField{ID: 8, Name: "lower_int", Type: 
iceberg.PrimitiveTypes.Int32},
@@ -951,7 +951,7 @@ func 
TestDecodeScanTasksAcceptsPointerAndUnknownPartitionTransforms(t *testing.T
 
 func TestDecodePartitionLogicalMetadata(t *testing.T) {
        t.Parallel()
-       decimalType := iceberg.DecimalTypeOf(9, 2)
+       decimalType := iceberg.MustDecimalTypeOf(9, 2)
        for _, tt := range []struct {
                name        string
                typ         iceberg.Type
@@ -961,7 +961,7 @@ func TestDecodePartitionLogicalMetadata(t *testing.T) {
        }{
                {name: "unpartitioned"},
                {name: "integer", typ: iceberg.PrimitiveTypes.Int64, raw: `34`, 
want: int64(34)},
-               {name: "fixed", typ: iceberg.FixedTypeOf(4), raw: `"78797A21"`, 
want: []byte("xyz!")},
+               {name: "fixed", typ: iceberg.MustFixedTypeOf(4), raw: 
`"78797A21"`, want: []byte("xyz!")},
                {name: "null date", typ: iceberg.PrimitiveTypes.Date, raw: 
`null`},
                {name: "null decimal", typ: decimalType, raw: `null`},
                {name: "date", typ: iceberg.PrimitiveTypes.Date, raw: 
`"2026-07-17"`, want: mustLiteral(t, "2026-07-17", 
iceberg.PrimitiveTypes.Date).Any(), logicalType: atype.Date},
diff --git a/data_file_codec_bench_test.go b/data_file_codec_bench_test.go
index f7080065a..c118bc563 100644
--- a/data_file_codec_bench_test.go
+++ b/data_file_codec_bench_test.go
@@ -30,7 +30,7 @@ func BenchmarkDataFileSchemaCache(b *testing.B) {
                NestedField{ID: 1, Name: "id", Type: Int64Type{}},
                NestedField{ID: 2, Name: "category", Type: StringType{}},
                NestedField{ID: 3, Name: "ts", Type: TimestampType{}},
-               NestedField{ID: 4, Name: "price", Type: DecimalTypeOf(10, 2)},
+               NestedField{ID: 4, Name: "price", Type: MustDecimalTypeOf(10, 
2)},
                NestedField{ID: 5, Name: "nested", Type: &StructType{FieldList: 
[]NestedField{
                        {ID: 6, Name: "value", Type: StringType{}},
                }}},
diff --git a/data_file_codec_fingerprint_test.go 
b/data_file_codec_fingerprint_test.go
index 204b4a956..40603fe8a 100644
--- a/data_file_codec_fingerprint_test.go
+++ b/data_file_codec_fingerprint_test.go
@@ -48,11 +48,11 @@ func TestPartitionTypeFingerprintMatchesAvroConversion(t 
*testing.T) {
                VariantType{},
                GeometryType{},
                GeographyType{},
-               FixedTypeOf(8),
-               FixedTypeOf(16),
-               DecimalTypeOf(10, 2),
-               DecimalTypeOf(11, 2),
-               DecimalTypeOf(10, 3),
+               MustFixedTypeOf(8),
+               MustFixedTypeOf(16),
+               MustDecimalTypeOf(10, 2),
+               MustDecimalTypeOf(11, 2),
+               MustDecimalTypeOf(10, 3),
                &StructType{FieldList: []NestedField{{ID: 2, Name: "child", 
Type: StringType{}}}},
                &ListType{ElementID: 2, Element: StringType{}},
                &MapType{KeyID: 2, KeyType: StringType{}, ValueID: 3, 
ValueType: Int64Type{}},
@@ -90,11 +90,11 @@ func 
TestManifestEntrySchemaForMultipleParameterizedFields(t *testing.T) {
                        decimal Type
                        fixed   Type
                }{
-                       {"ordered", NewPartitionSpec(price, code), 
DecimalTypeOf(10, 2), FixedTypeOf(16)},
-                       {"reversed", NewPartitionSpec(code, price), 
DecimalTypeOf(10, 2), FixedTypeOf(16)},
-                       {"precision", NewPartitionSpec(price, code), 
DecimalTypeOf(11, 2), FixedTypeOf(16)},
-                       {"scale", NewPartitionSpec(price, code), 
DecimalTypeOf(10, 3), FixedTypeOf(16)},
-                       {"fixed_size", NewPartitionSpec(price, code), 
DecimalTypeOf(10, 2), FixedTypeOf(8)},
+                       {"ordered", NewPartitionSpec(price, code), 
MustDecimalTypeOf(10, 2), MustFixedTypeOf(16)},
+                       {"reversed", NewPartitionSpec(code, price), 
MustDecimalTypeOf(10, 2), MustFixedTypeOf(16)},
+                       {"precision", NewPartitionSpec(price, code), 
MustDecimalTypeOf(11, 2), MustFixedTypeOf(16)},
+                       {"scale", NewPartitionSpec(price, code), 
MustDecimalTypeOf(10, 3), MustFixedTypeOf(16)},
+                       {"fixed_size", NewPartitionSpec(price, code), 
MustDecimalTypeOf(10, 2), MustFixedTypeOf(8)},
                } {
                        t.Run(tc.name+"/v"+strconv.Itoa(version), func(t 
*testing.T) {
                                t.Parallel()
@@ -120,8 +120,8 @@ func 
TestManifestEntrySchemaForMultipleParameterizedFields(t *testing.T) {
 
 func TestPartitionSchemaFingerprintNameBoundaries(t *testing.T) {
        schema := NewSchema(1,
-               NestedField{ID: 1, Name: "source_price", Type: 
DecimalTypeOf(10, 2)},
-               NestedField{ID: 2, Name: "source_code", Type: FixedTypeOf(16)},
+               NestedField{ID: 1, Name: "source_price", Type: 
MustDecimalTypeOf(10, 2)},
+               NestedField{ID: 2, Name: "source_code", Type: 
MustFixedTypeOf(16)},
        )
        // Exercise the key's length prefixes independently of Avro name 
validation.
        names := []string{"a", "ab", "1:a", "a:q10:2:", "f16:", "λ"}
diff --git a/data_file_codec_test.go b/data_file_codec_test.go
index 74501ec10..013bd58fb 100644
--- a/data_file_codec_test.go
+++ b/data_file_codec_test.go
@@ -299,7 +299,7 @@ func TestCloneDataFileAvroFieldsCopiesOnlyAvroFields(t 
*testing.T) {
 
 func TestMarshalAvroEntryDecimalPartitionRoundTrip(t *testing.T) {
        schema := NewSchema(0,
-               NestedField{ID: 1, Name: "price", Type: DecimalTypeOf(10, 2)},
+               NestedField{ID: 1, Name: "price", Type: MustDecimalTypeOf(10, 
2)},
        )
        spec := NewPartitionSpecID(1,
                PartitionField{SourceIDs: []int{1}, FieldID: 1000, Name: 
"price", Transform: IdentityTransform{}},
@@ -501,8 +501,8 @@ func TestManifestEntrySchemaForMatchesPartitionAvroShape(t 
*testing.T) {
                UUIDType{},
                BooleanType{},
                BinaryType{},
-               FixedTypeOf(8), FixedTypeOf(16),
-               DecimalTypeOf(10, 2), DecimalTypeOf(11, 2), DecimalTypeOf(10, 
3),
+               MustFixedTypeOf(8), MustFixedTypeOf(16),
+               MustDecimalTypeOf(10, 2), MustDecimalTypeOf(11, 2), 
MustDecimalTypeOf(10, 3),
                UnknownType{},
        }
        for _, version := range []int{1, 2, 3} {
diff --git a/expr_json_test.go b/expr_json_test.go
index cdf0b2b2d..7dfc011c7 100644
--- a/expr_json_test.go
+++ b/expr_json_test.go
@@ -155,7 +155,7 @@ func TestMarshalExpressionTypedLiterals(t *testing.T) {
                {"date", mustLit(t, "2022-08-14", iceberg.PrimitiveTypes.Date), 
`{"type":"eq","term":"d","value":"2022-08-14"}`},
                {"uuid", 
iceberg.UUIDLiteral(uuid.MustParse("f79c3e09-677c-4bbd-a479-3f349cb785e7")), 
`{"type":"eq","term":"d","value":"f79c3e09-677c-4bbd-a479-3f349cb785e7"}`},
                {"binary", iceberg.BinaryLiteral([]byte{0x01, 0x02, 0x03}), 
`{"type":"eq","term":"d","value":"010203"}`},
-               {"decimal", mustLit(t, "3.14", iceberg.DecimalTypeOf(9, 2)), 
`{"type":"eq","term":"d","value":"3.14"}`},
+               {"decimal", mustLit(t, "3.14", iceberg.MustDecimalTypeOf(9, 
2)), `{"type":"eq","term":"d","value":"3.14"}`},
        }
 
        for _, tt := range tests {
@@ -675,7 +675,7 @@ func TestUnmarshalExpressionLiteralWrapperErrors(t 
*testing.T) {
 // doesn't match the column's declared length.
 func TestUnmarshalExpressionFixedLength(t *testing.T) {
        schema := iceberg.NewSchema(0,
-               iceberg.NestedField{ID: 1, Name: "f", Type: 
iceberg.FixedTypeOf(4)},
+               iceberg.NestedField{ID: 1, Name: "f", Type: 
iceberg.MustFixedTypeOf(4)},
        )
        _, err := 
iceberg.ParseExpr([]byte(`{"type":"eq","term":"f","value":"0102"}`), schema)
        require.ErrorIs(t, err, iceberg.ErrInvalidArgument)
diff --git a/exprs_test.go b/exprs_test.go
index 2ccd54a81..5286b0f8a 100644
--- a/exprs_test.go
+++ b/exprs_test.go
@@ -251,11 +251,11 @@ func TestRefTypes(t *testing.T) {
                iceberg.NestedField{ID: 6, Name: "f", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 7, Name: "g", Type: 
iceberg.PrimitiveTypes.Time},
                iceberg.NestedField{ID: 8, Name: "h", Type: 
iceberg.PrimitiveTypes.Timestamp},
-               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.DecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
                iceberg.NestedField{ID: 10, Name: "j", Type: 
iceberg.PrimitiveTypes.String},
                iceberg.NestedField{ID: 11, Name: "k", Type: 
iceberg.PrimitiveTypes.Binary},
                iceberg.NestedField{ID: 12, Name: "l", Type: 
iceberg.PrimitiveTypes.UUID},
-               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.FixedTypeOf(5)},
+               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.MustFixedTypeOf(5)},
                iceberg.NestedField{ID: 14, Name: "n", Type: 
iceberg.VariantType{}},
                iceberg.NestedField{ID: 15, Name: "o", Type: 
iceberg.PrimitiveTypes.TimestampNs},
                iceberg.NestedField{ID: 16, Name: "p", Type: 
iceberg.PrimitiveTypes.TimestampTzNs})
@@ -334,7 +334,7 @@ func TestRefTypes(t *testing.T) {
                        require.NoError(t, err)
 
                        assert.Equal(t, iceberg.OpEQ, fx.Op())
-                       assert.True(t, 
fx.(iceberg.BoundLiteralPredicate).Literal().Type().Equals(iceberg.FixedTypeOf(5)))
+                       assert.True(t, 
fx.(iceberg.BoundLiteralPredicate).Literal().Type().Equals(iceberg.MustFixedTypeOf(5)))
                })
 
                t.Run("uuid", func(t *testing.T) {
@@ -412,9 +412,9 @@ func TestRefTypes(t *testing.T) {
                        require.NoError(t, err)
 
                        assert.Equal(t, iceberg.OpIn, fx.Op())
-                       assert.True(t, 
fx.(iceberg.BoundSetPredicate).Ref().Type().Equals(iceberg.FixedTypeOf(5)))
+                       assert.True(t, 
fx.(iceberg.BoundSetPredicate).Ref().Type().Equals(iceberg.MustFixedTypeOf(5)))
                        for _, v := range 
fx.(iceberg.BoundSetPredicate).Literals().Members() {
-                               assert.True(t, 
v.Type().Equals(iceberg.FixedTypeOf(5)))
+                               assert.True(t, 
v.Type().Equals(iceberg.MustFixedTypeOf(5)))
                        }
                })
 
@@ -544,7 +544,7 @@ func TestInNotInSimplifications(t *testing.T) {
                        },
                        {
                                name: "fixed",
-                               typ:  iceberg.FixedTypeOf(16),
+                               typ:  iceberg.MustFixedTypeOf(16),
                                lits: func(first, second []byte) 
[]iceberg.Literal {
                                        return 
[]iceberg.Literal{iceberg.NewLiteral(first), iceberg.NewLiteral(second)}
                                },
@@ -848,7 +848,7 @@ func TestToString(t *testing.T) {
                iceberg.NestedField{ID: 5, Name: "e", Type: 
iceberg.PrimitiveTypes.Int32},
                iceberg.NestedField{ID: 6, Name: "f", Type: 
iceberg.PrimitiveTypes.Int32},
                iceberg.NestedField{ID: 7, Name: "g", Type: 
iceberg.PrimitiveTypes.Float32},
-               iceberg.NestedField{ID: 8, Name: "h", Type: 
iceberg.DecimalTypeOf(8, 4)},
+               iceberg.NestedField{ID: 8, Name: "h", Type: 
iceberg.MustDecimalTypeOf(8, 4)},
                iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.PrimitiveTypes.UUID},
                iceberg.NestedField{ID: 10, Name: "j", Type: 
iceberg.PrimitiveTypes.Bool},
                iceberg.NestedField{ID: 11, Name: "k", Type: 
iceberg.PrimitiveTypes.Bool},
diff --git a/literals_test.go b/literals_test.go
index c3bcb941a..7b52350fd 100644
--- a/literals_test.go
+++ b/literals_test.go
@@ -81,15 +81,15 @@ func TestIntToDecimalConversion(t *testing.T) {
                val iceberg.Decimal
        }{
                {
-                       iceberg.DecimalTypeOf(9, 0),
+                       iceberg.MustDecimalTypeOf(9, 0),
                        iceberg.Decimal{Val: decimal128.FromI64(34), Scale: 0},
                },
                {
-                       iceberg.DecimalTypeOf(9, 2),
+                       iceberg.MustDecimalTypeOf(9, 2),
                        iceberg.Decimal{Val: decimal128.FromI64(3400), Scale: 
2},
                },
                {
-                       iceberg.DecimalTypeOf(9, 4),
+                       iceberg.MustDecimalTypeOf(9, 4),
                        iceberg.Decimal{Val: decimal128.FromI64(340000), Scale: 
4},
                },
        }
@@ -453,23 +453,23 @@ func TestFloat64toFloat32OutsideBounds(t *testing.T) {
 func TestDecimalToDecimalConversion(t *testing.T) {
        lit := iceberg.NewLiteral(iceberg.Decimal{Val: 
decimal128.FromI64(3411), Scale: 2})
 
-       v, err := lit.To(iceberg.DecimalTypeOf(9, 2))
+       v, err := lit.To(iceberg.MustDecimalTypeOf(9, 2))
        require.NoError(t, err)
        assert.Equal(t, lit, v)
 
-       v, err = lit.To(iceberg.DecimalTypeOf(11, 2))
+       v, err = lit.To(iceberg.MustDecimalTypeOf(11, 2))
        require.NoError(t, err)
        assert.Equal(t, lit, v)
 
-       _, err = lit.To(iceberg.DecimalTypeOf(9, 0))
+       _, err = lit.To(iceberg.MustDecimalTypeOf(9, 0))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 0)")
 
-       _, err = lit.To(iceberg.DecimalTypeOf(9, 1))
+       _, err = lit.To(iceberg.MustDecimalTypeOf(9, 1))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 1)")
 
-       _, err = lit.To(iceberg.DecimalTypeOf(9, 3))
+       _, err = lit.To(iceberg.MustDecimalTypeOf(9, 3))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "could not convert 34.11 to decimal(9, 3)")
 }
@@ -797,7 +797,7 @@ func TestStringLiteralConversion(t *testing.T) {
 }
 
 func TestLiteralIdentityConversions(t *testing.T) {
-       fixedLit, _ := iceberg.NewLiteral([]byte{0x01, 0x02, 
0x03}).To(iceberg.FixedTypeOf(3))
+       fixedLit, _ := iceberg.NewLiteral([]byte{0x01, 0x02, 
0x03}).To(iceberg.MustFixedTypeOf(3))
 
        tests := []struct {
                lit iceberg.Literal
@@ -810,7 +810,7 @@ func TestLiteralIdentityConversions(t *testing.T) {
                {iceberg.NewLiteral(float64(3.5028235e38)), 
iceberg.PrimitiveTypes.Float64},
                {
                        iceberg.NewLiteral(iceberg.Decimal{Val: 
decimal128.FromI64(3455), Scale: 2}),
-                       iceberg.DecimalTypeOf(9, 2),
+                       iceberg.MustDecimalTypeOf(9, 2),
                },
                {iceberg.NewLiteral(iceberg.Date(19079)), 
iceberg.PrimitiveTypes.Date},
                {
@@ -819,7 +819,7 @@ func TestLiteralIdentityConversions(t *testing.T) {
                },
                {iceberg.NewLiteral("abc"), iceberg.PrimitiveTypes.String},
                {iceberg.NewLiteral(uuid.New()), iceberg.PrimitiveTypes.UUID},
-               {fixedLit, iceberg.FixedTypeOf(3)},
+               {fixedLit, iceberg.MustFixedTypeOf(3)},
                {iceberg.NewLiteral([]byte{0x01, 0x02, 0x03}), 
iceberg.PrimitiveTypes.Binary},
        }
 
@@ -1067,14 +1067,14 @@ func TestFixedLiteral(t *testing.T) {
        assert.Equal(t, 0, cmp(fixedLit013, fixedLit013))
 
        testUuid := uuid.New()
-       lit, err := iceberg.NewLiteral(testUuid[:]).To(iceberg.FixedTypeOf(16))
+       lit, err := 
iceberg.NewLiteral(testUuid[:]).To(iceberg.MustFixedTypeOf(16))
        require.NoError(t, err)
        uuidLit, err := lit.To(iceberg.PrimitiveTypes.UUID)
        require.NoError(t, err)
 
        assert.EqualValues(t, uuidLit, testUuid)
 
-       fixedUuid, err := uuidLit.To(iceberg.FixedTypeOf(16))
+       fixedUuid, err := uuidLit.To(iceberg.MustFixedTypeOf(16))
        require.NoError(t, err)
        assert.EqualValues(t, testUuid[:], fixedUuid)
 
@@ -1107,15 +1107,15 @@ func TestBinaryLiteral(t *testing.T) {
 
 func TestBinaryLiteralConversions(t *testing.T) {
        binLit012 := iceberg.NewLiteral([]byte{0x00, 0x01, 0x02})
-       fixed, err := binLit012.To(iceberg.FixedTypeOf(3))
+       fixed, err := binLit012.To(iceberg.MustFixedTypeOf(3))
        require.NoError(t, err)
        assert.Equal(t, iceberg.FixedLiteral{0x00, 0x01, 0x02}, fixed)
 
-       _, err = binLit012.To(iceberg.FixedTypeOf(4))
+       _, err = binLit012.To(iceberg.MustFixedTypeOf(4))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "cannot convert BinaryLiteral to fixed[4], 
different length - 3 <> 4")
 
-       _, err = binLit012.To(iceberg.FixedTypeOf(2))
+       _, err = binLit012.To(iceberg.MustFixedTypeOf(2))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "cannot convert BinaryLiteral to fixed[2], 
different length - 3 <> 2")
 
@@ -1151,11 +1151,11 @@ func TestInvalidBoolLiteralConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Time,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
                iceberg.PrimitiveTypes.Binary,
-               iceberg.FixedTypeOf(2),
+               iceberg.MustFixedTypeOf(2),
        })
 }
 
@@ -1210,7 +1210,7 @@ func TestInvalidNumericConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Bool,
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1218,7 +1218,7 @@ func TestInvalidNumericConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Bool,
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1232,7 +1232,7 @@ func TestInvalidNumericConversions(t *testing.T) {
                iceberg.PrimitiveTypes.TimestampTz,
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1246,7 +1246,7 @@ func TestInvalidNumericConversions(t *testing.T) {
                iceberg.PrimitiveTypes.TimestampTz,
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1259,7 +1259,7 @@ func TestInvalidNumericConversions(t *testing.T) {
                        iceberg.PrimitiveTypes.TimestampTz,
                        iceberg.PrimitiveTypes.String,
                        iceberg.PrimitiveTypes.UUID,
-                       iceberg.FixedTypeOf(1),
+                       iceberg.MustFixedTypeOf(1),
                        iceberg.PrimitiveTypes.Binary,
                })
 }
@@ -1275,10 +1275,10 @@ func TestInvalidDateTimeLiteralConversions(t 
*testing.T) {
                iceberg.PrimitiveTypes.Time,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1292,10 +1292,10 @@ func TestInvalidDateTimeLiteralConversions(t 
*testing.T) {
                iceberg.PrimitiveTypes.Date,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 
@@ -1307,17 +1307,17 @@ func TestInvalidDateTimeLiteralConversions(t 
*testing.T) {
                iceberg.PrimitiveTypes.Float32,
                iceberg.PrimitiveTypes.Float64,
                iceberg.PrimitiveTypes.Time,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
                iceberg.PrimitiveTypes.Binary,
        })
 }
 
 func TestInvalidStringLiteralConversions(t *testing.T) {
        testInvalidLiteralConversions(t, iceberg.NewLiteral("abc"), 
[]iceberg.Type{
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
        })
 }
 
@@ -1332,12 +1332,12 @@ func TestInvalidBinaryLiteralConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Time,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
-               iceberg.FixedTypeOf(1),
+               iceberg.MustFixedTypeOf(1),
        })
 
-       lit, _ := iceberg.NewLiteral([]byte{0x00, 0x01, 
0x02}).To(iceberg.FixedTypeOf(3))
+       lit, _ := iceberg.NewLiteral([]byte{0x00, 0x01, 
0x02}).To(iceberg.MustFixedTypeOf(3))
        testInvalidLiteralConversions(t, lit, []iceberg.Type{
                iceberg.PrimitiveTypes.Bool,
                iceberg.PrimitiveTypes.Int32,
@@ -1348,7 +1348,7 @@ func TestInvalidBinaryLiteralConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Time,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
        })
@@ -1363,7 +1363,7 @@ func TestInvalidBinaryLiteralConversions(t *testing.T) {
                iceberg.PrimitiveTypes.Time,
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
        })
@@ -1382,11 +1382,11 @@ func TestInvalidVariantLiteralConversions(t *testing.T) 
{
                        iceberg.PrimitiveTypes.Time,
                        iceberg.PrimitiveTypes.Timestamp,
                        iceberg.PrimitiveTypes.TimestampTz,
-                       iceberg.DecimalTypeOf(9, 2),
+                       iceberg.MustDecimalTypeOf(9, 2),
                        iceberg.PrimitiveTypes.String,
                        iceberg.PrimitiveTypes.UUID,
                        iceberg.PrimitiveTypes.Binary,
-                       iceberg.FixedTypeOf(2),
+                       iceberg.MustFixedTypeOf(2),
                })
        }
 
@@ -1401,7 +1401,7 @@ func TestInvalidVariantLiteralConversions(t *testing.T) {
        assert.ErrorContains(t, err, "VariantLiteral: could not cast value: 
Int32Literal to string")
 
        // a cast error from the underlying literal that lacks ErrBadCast still 
gets it
-       _, err = variantLiteralOf(t, float32(1e30)).To(iceberg.DecimalTypeOf(9, 
2))
+       _, err = variantLiteralOf(t, 
float32(1e30)).To(iceberg.MustDecimalTypeOf(9, 2))
        assert.ErrorIs(t, err, iceberg.ErrBadCast)
        assert.ErrorContains(t, err, "VariantLiteral: ")
 }
@@ -1417,7 +1417,7 @@ func TestBadStringLiteralCasts(t *testing.T) {
                iceberg.PrimitiveTypes.Timestamp,
                iceberg.PrimitiveTypes.TimestampTz,
                iceberg.PrimitiveTypes.Bool,
-               iceberg.DecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(9, 2),
                iceberg.PrimitiveTypes.UUID,
        }
 
@@ -1500,25 +1500,25 @@ func TestUnmarshalBinary(t *testing.T) {
                        []byte{0xf7, 0x9c, 0x3e, 0x09, 0x67, 0x7c, 0x4b, 0xbd, 
0xa4, 0x79, 0x3f, 0x34, 0x9c, 0xb7, 0x85, 0xe7},
                        iceberg.UUIDLiteral(uuid.UUID{0xf7, 0x9c, 0x3e, 0x09, 
0x67, 0x7c, 0x4b, 0xbd, 0xa4, 0x79, 0x3f, 0x34, 0x9c, 0xb7, 0x85, 0xe7}),
                },
-               {iceberg.FixedTypeOf(3), []byte("foo"), 
iceberg.FixedLiteral([]byte("foo"))},
+               {iceberg.MustFixedTypeOf(3), []byte("foo"), 
iceberg.FixedLiteral([]byte("foo"))},
                {iceberg.PrimitiveTypes.Binary, []byte("foo"), 
iceberg.BinaryLiteral([]byte("foo"))},
                {
-                       iceberg.DecimalTypeOf(5, 2),
+                       iceberg.MustDecimalTypeOf(5, 2),
                        []byte{0x30, 0x39},
                        iceberg.DecimalLiteral{Scale: 2, Val: 
decimal128.FromU64(12345)},
                },
                {
-                       iceberg.DecimalTypeOf(7, 4),
+                       iceberg.MustDecimalTypeOf(7, 4),
                        []byte{0x12, 0xd6, 0x87},
                        iceberg.DecimalLiteral{Scale: 4, Val: 
decimal128.FromU64(1234567)},
                },
                {
-                       iceberg.DecimalTypeOf(7, 4),
+                       iceberg.MustDecimalTypeOf(7, 4),
                        []byte{0xff, 0xed, 0x29, 0x79},
                        iceberg.DecimalLiteral{Scale: 4, Val: 
decimal128.FromI64(-1234567)},
                },
                {
-                       iceberg.DecimalTypeOf(8, 2),
+                       iceberg.MustDecimalTypeOf(8, 2),
                        []byte{0x00, 0xbc, 0x61, 0x4e},
                        iceberg.DecimalLiteral{Scale: 2, Val: 
decimal128.FromI64(12345678)},
                },
@@ -1554,7 +1554,7 @@ func TestLiteralFromBytesFixedWidth(t *testing.T) {
 
        for _, test := range tests {
                t.Run(test.name, func(t *testing.T) {
-                       literal, err := 
iceberg.LiteralFromBytes(iceberg.FixedTypeOf(4), test.data)
+                       literal, err := 
iceberg.LiteralFromBytes(iceberg.MustFixedTypeOf(4), test.data)
                        if test.errContains != "" {
                                require.ErrorIs(t, err, 
iceberg.ErrInvalidBinSerialization)
                                if test.oversized {
@@ -1631,10 +1631,10 @@ func TestRoundTripLiteralBinary(t *testing.T) {
                        []byte{0xf7, 0x9c, 0x3e, 0x09, 0x67, 0x7c, 0x4b, 0xbd, 
0xa4, 0x79, 0x3f, 0x34, 0x9c, 0xb7, 0x85, 0xe7},
                        iceberg.UUIDLiteral(uuid.UUID{0xf7, 0x9c, 0x3e, 0x09, 
0x67, 0x7c, 0x4b, 0xbd, 0xa4, 0x79, 0x3f, 0x34, 0x9c, 0xb7, 0x85, 0xe7}),
                },
-               {iceberg.FixedTypeOf(3), []byte("foo"), 
iceberg.FixedLiteral([]byte("foo"))},
+               {iceberg.MustFixedTypeOf(3), []byte("foo"), 
iceberg.FixedLiteral([]byte("foo"))},
                {iceberg.PrimitiveTypes.Binary, []byte("foo"), 
iceberg.BinaryLiteral([]byte("foo"))},
                {
-                       iceberg.DecimalTypeOf(5, 2),
+                       iceberg.MustDecimalTypeOf(5, 2),
                        []byte{0x30, 0x39},
                        iceberg.DecimalLiteral{Scale: 2, Val: 
decimal128.FromU64(12345)},
                },
@@ -1642,7 +1642,7 @@ func TestRoundTripLiteralBinary(t *testing.T) {
                // 1234567 is 00010010|11010110|10000111 in binary
                // 00010010 -> 18, 11010110 -> 214, 10000111 -> 135
                {
-                       iceberg.DecimalTypeOf(7, 4),
+                       iceberg.MustDecimalTypeOf(7, 4),
                        []byte{0x12, 0xd6, 0x87},
                        iceberg.DecimalLiteral{Scale: 4, Val: 
decimal128.FromU64(1234567)},
                },
@@ -1650,15 +1650,15 @@ func TestRoundTripLiteralBinary(t *testing.T) {
                // -1234567 is 11101101|00101001|01111001 in binary
                // 11101101 -> 237, 00101001 -> 41, 01111001 -> 121
                {
-                       iceberg.DecimalTypeOf(7, 4),
+                       iceberg.MustDecimalTypeOf(7, 4),
                        []byte{0xed, 0x29, 0x79},
                        iceberg.DecimalLiteral{Scale: 4, Val: 
decimal128.FromI64(-1234567)},
                },
                // test empty byte in decimal
                // 11 is 00001011 in binary
                // 00001011 -> 11
-               {iceberg.DecimalTypeOf(10, 3), []byte{0x0b}, 
iceberg.DecimalLiteral{Scale: 3, Val: decimal128.FromU64(11)}},
-               {iceberg.DecimalTypeOf(4, 2), []byte{0x04, 0xd2}, 
iceberg.DecimalLiteral{Scale: 2, Val: decimal128.FromU64(1234)}},
+               {iceberg.MustDecimalTypeOf(10, 3), []byte{0x0b}, 
iceberg.DecimalLiteral{Scale: 3, Val: decimal128.FromU64(11)}},
+               {iceberg.MustDecimalTypeOf(4, 2), []byte{0x04, 0xd2}, 
iceberg.DecimalLiteral{Scale: 2, Val: decimal128.FromU64(1234)}},
        }
 
        for _, tt := range tests {
@@ -1683,7 +1683,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                val string
        }{
                {
-                       iceberg.DecimalTypeOf(38, 21),
+                       iceberg.MustDecimalTypeOf(38, 21),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe9, 0x18, 0x30, 
0x73, 0xb9, 0x1e,
                                0x7e, 0xa2, 0xb3, 0x6a, 0x83,
@@ -1691,7 +1691,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "12345678912345678.123456789123456789123",
                },
                {
-                       iceberg.DecimalTypeOf(38, 22),
+                       iceberg.MustDecimalTypeOf(38, 22),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe9, 0x16, 0xbb, 
0x01, 0x2f,
                                0x4c, 0xc3, 0x2b, 0x42, 0x29, 0x22,
@@ -1699,7 +1699,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "1234567891234567.1234567891234567891234",
                },
                {
-                       iceberg.DecimalTypeOf(38, 23),
+                       iceberg.MustDecimalTypeOf(38, 23),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe9, 0x0a, 0x42, 
0xa1, 0xad,
                                0xe5, 0x2b, 0x33, 0x15, 0x9b, 0x59,
@@ -1707,7 +1707,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "123456789123456.12345678912345678912345",
                },
                {
-                       iceberg.DecimalTypeOf(38, 24),
+                       iceberg.MustDecimalTypeOf(38, 24),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe8, 0xa2, 0xbb, 
0xe9, 0x67,
                                0xba, 0x86, 0x77, 0xd8, 0x11, 0x80,
@@ -1715,7 +1715,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "12345678912345.123456789123456789123456",
                },
                {
-                       iceberg.DecimalTypeOf(38, 25),
+                       iceberg.MustDecimalTypeOf(38, 25),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe5, 0x6b, 0x3a, 
0xd2, 0x78,
                                0xdd, 0x04, 0xc8, 0x70, 0xaf, 0x07,
@@ -1723,7 +1723,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "1234567891234.1234567891234567891234567",
                },
                {
-                       iceberg.DecimalTypeOf(38, 26),
+                       iceberg.MustDecimalTypeOf(38, 26),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xcd, 0x85, 0xc5, 
0x03, 0x38, 0x37,
                                0x3c, 0x38, 0x66, 0xd6, 0x4e,
@@ -1731,7 +1731,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "123456789123.12345678912345678912345678",
                },
                {
-                       iceberg.DecimalTypeOf(38, 27),
+                       iceberg.MustDecimalTypeOf(38, 27),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0x31, 0x46, 0xfd, 
0xc7, 0x79,
                                0xca, 0x39, 0x7c, 0x04, 0x5f, 0x15,
@@ -1739,7 +1739,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "12345678912.123456789123456789123456789",
                },
                {
-                       iceberg.DecimalTypeOf(38, 28),
+                       iceberg.MustDecimalTypeOf(38, 28),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x10, 0x52, 0x01, 0x72, 
0x11, 0xda,
                                0x08, 0x5b, 0x08, 0x2b, 0xb6, 0xd3,
@@ -1747,7 +1747,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "1234567891.1234567891234567891234567891",
                },
                {
-                       iceberg.DecimalTypeOf(38, 29),
+                       iceberg.MustDecimalTypeOf(38, 29),
                        []byte{
                                0x09, 0x49, 0xb0, 0xf7, 0x13, 0xe9, 0x18, 0x5b, 
0x37, 0xc1,
                                0x78, 0x0b, 0x91, 0xb5, 0x24, 0x40,
@@ -1755,7 +1755,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "123456789.12345678912345678912345678912",
                },
                {
-                       iceberg.DecimalTypeOf(38, 30),
+                       iceberg.MustDecimalTypeOf(38, 30),
                        []byte{
                                0x09, 0x49, 0xb0, 0xed, 0x1e, 0xdf, 0x80, 0x03, 
0x47, 0x3b,
                                0x16, 0x9b, 0xf1, 0x13, 0x6a, 0x83,
@@ -1763,7 +1763,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "12345678.123456789123456789123456789123",
                },
                {
-                       iceberg.DecimalTypeOf(38, 31),
+                       iceberg.MustDecimalTypeOf(38, 31),
                        []byte{
                                0x09, 0x49, 0xb0, 0x96, 0x2b, 0xac, 0x29, 0x64, 
0x28, 0x70,
                                0x36, 0x29, 0xea, 0xc2, 0x29, 0x22,
@@ -1771,7 +1771,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "1234567.1234567891234567891234567891234",
                },
                {
-                       iceberg.DecimalTypeOf(38, 32),
+                       iceberg.MustDecimalTypeOf(38, 32),
                        []byte{
                                0x09, 0x49, 0xad, 0xae, 0xe3, 0x68, 0xe7, 0x4f, 
0xb5, 0x14,
                                0xbc, 0xdc, 0x2b, 0x95, 0x9b, 0x59,
@@ -1779,7 +1779,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "123456.12345678912345678912345678912345",
                },
                {
-                       iceberg.DecimalTypeOf(38, 33),
+                       iceberg.MustDecimalTypeOf(38, 33),
                        []byte{
                                0x09, 0x49, 0x95, 0x94, 0x3e, 0x35, 0x93, 0xde, 
0xb9, 0x2e,
                                0xef, 0x53, 0xb3, 0xd8, 0x11, 0x80,
@@ -1787,7 +1787,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "12345.123456789123456789123456789123456",
                },
                {
-                       iceberg.DecimalTypeOf(38, 34),
+                       iceberg.MustDecimalTypeOf(38, 34),
                        []byte{
                                0x09, 0x48, 0xd5, 0xd7, 0x90, 0x78, 0xdf, 0x08, 
0x1a, 0xf6,
                                0x43, 0x09, 0x06, 0x70, 0xaf, 0x07,
@@ -1795,7 +1795,7 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "1234.1234567891234567891234567891234567",
                },
                {
-                       iceberg.DecimalTypeOf(38, 35),
+                       iceberg.MustDecimalTypeOf(38, 35),
                        []byte{
                                0x09, 0x43, 0x45, 0x82, 0x85, 0xc7, 0x56, 0x66, 
0x24, 0x4d,
                                0x16, 0x82, 0x40, 0x66, 0xd6, 0x4e,
@@ -1803,57 +1803,57 @@ func TestLargeDecimalRoundTrip(t *testing.T) {
                        "123.12345678912345678912345678912345678",
                },
                {
-                       iceberg.DecimalTypeOf(21, 16),
+                       iceberg.MustDecimalTypeOf(21, 16),
                        []byte{0x06, 0xb1, 0x3a, 0xe3, 0xc4, 0x4e, 0x94, 0xaf, 
0x07},
                        "12345.1234567891234567",
                },
                {
-                       iceberg.DecimalTypeOf(22, 17),
+                       iceberg.MustDecimalTypeOf(22, 17),
                        []byte{0x42, 0xec, 0x4c, 0xe5, 0xab, 0x11, 0xce, 0xd6, 
0x4e},
                        "12345.12345678912345678",
                },
                {
-                       iceberg.DecimalTypeOf(23, 18),
+                       iceberg.MustDecimalTypeOf(23, 18),
                        []byte{0x02, 0x9d, 0x3b, 0x00, 0xf8, 0xae, 0xb2, 0x14, 
0x5f, 0x15},
                        "12345.123456789123456789",
                },
                {
-                       iceberg.DecimalTypeOf(24, 19),
+                       iceberg.MustDecimalTypeOf(24, 19),
                        []byte{0x1a, 0x24, 0x4e, 0x09, 0xb6, 0xd2, 0xf4, 0xcb, 
0xb6, 0xd3},
                        "12345.1234567891234567891",
                },
                {
-                       iceberg.DecimalTypeOf(25, 20),
+                       iceberg.MustDecimalTypeOf(25, 20),
                        []byte{0x01, 0x05, 0x6b, 0x0c, 0x61, 0x24, 0x3d, 0x8f, 
0xf5, 0x24, 0x40},
                        "12345.12345678912345678912",
                },
                {
-                       iceberg.DecimalTypeOf(26, 21),
+                       iceberg.MustDecimalTypeOf(26, 21),
                        []byte{0x0a, 0x36, 0x2e, 0x7b, 0xcb, 0x6a, 0x67, 0x9f, 
0x93, 0x6a, 0x83},
                        "12345.123456789123456789123",
                },
                {
-                       iceberg.DecimalTypeOf(27, 22),
+                       iceberg.MustDecimalTypeOf(27, 22),
                        []byte{0x66, 0x1d, 0xd0, 0xd5, 0xf2, 0x28, 0x0c, 0x3b, 
0xc2, 0x29, 0x22},
                        "12345.1234567891234567891234",
                },
                {
-                       iceberg.DecimalTypeOf(28, 23),
+                       iceberg.MustDecimalTypeOf(28, 23),
                        []byte{0x03, 0xfd, 0x2a, 0x28, 0x5b, 0x75, 0x90, 0x7a, 
0x55, 0x95, 0x9b, 0x59},
                        "12345.12345678912345678912345",
                },
                {
-                       iceberg.DecimalTypeOf(29, 24),
+                       iceberg.MustDecimalTypeOf(29, 24),
                        []byte{0x27, 0xe3, 0xa5, 0x93, 0x92, 0x97, 0xa4, 0xc7, 
0x57, 0xd8, 0x11, 0x80},
                        "12345.123456789123456789123456",
                },
                {
-                       iceberg.DecimalTypeOf(30, 25),
+                       iceberg.MustDecimalTypeOf(30, 25),
                        []byte{0x01, 0x8e, 0xe4, 0x77, 0xc3, 0xb9, 0xec, 0x6f, 
0xc9, 0x6e, 0x70, 0xaf, 0x07},
                        "12345.1234567891234567891234567",
                },
                {
-                       iceberg.DecimalTypeOf(31, 26),
+                       iceberg.MustDecimalTypeOf(31, 26),
                        []byte{0x0f, 0x94, 0xec, 0xad, 0xa5, 0x43, 0x3c, 0x5d, 
0xde, 0x50, 0x66, 0xd6, 0x4e},
                        "12345.12345678912345678912345678",
                },
@@ -1882,16 +1882,16 @@ func TestDecimalMaxMinRoundTrip(t *testing.T) {
                typ iceberg.DecimalType
                v   string
        }{
-               {iceberg.DecimalTypeOf(6, 2), "9999.99"},
-               {iceberg.DecimalTypeOf(10, 10), ".9999999999"},
-               {iceberg.DecimalTypeOf(2, 1), "9.9"},
-               {iceberg.DecimalTypeOf(38, 37), 
"9.9999999999999999999999999999999999999"},
-               {iceberg.DecimalTypeOf(20, 1), "9999999999999999999.9"},
-               {iceberg.DecimalTypeOf(6, 2), "-9999.99"},
-               {iceberg.DecimalTypeOf(10, 10), "-.9999999999"},
-               {iceberg.DecimalTypeOf(2, 1), "-9.9"},
-               {iceberg.DecimalTypeOf(38, 37), 
"-9.9999999999999999999999999999999999999"},
-               {iceberg.DecimalTypeOf(20, 1), "-9999999999999999999.9"},
+               {iceberg.MustDecimalTypeOf(6, 2), "9999.99"},
+               {iceberg.MustDecimalTypeOf(10, 10), ".9999999999"},
+               {iceberg.MustDecimalTypeOf(2, 1), "9.9"},
+               {iceberg.MustDecimalTypeOf(38, 37), 
"9.9999999999999999999999999999999999999"},
+               {iceberg.MustDecimalTypeOf(20, 1), "9999999999999999999.9"},
+               {iceberg.MustDecimalTypeOf(6, 2), "-9999.99"},
+               {iceberg.MustDecimalTypeOf(10, 10), "-.9999999999"},
+               {iceberg.MustDecimalTypeOf(2, 1), "-9.9"},
+               {iceberg.MustDecimalTypeOf(38, 37), 
"-9.9999999999999999999999999999999999999"},
+               {iceberg.MustDecimalTypeOf(20, 1), "-9999999999999999999.9"},
        }
 
        for _, tt := range tests {
diff --git a/manifest_partition_bench_test.go b/manifest_partition_bench_test.go
index a8e0cdc26..78b014371 100644
--- a/manifest_partition_bench_test.go
+++ b/manifest_partition_bench_test.go
@@ -40,9 +40,9 @@ func BenchmarkPartitionFieldStatsUpdate(b *testing.B) {
                {name: "binary_repeated_16", typ: PrimitiveTypes.Binary, 
pattern: "repeated", width: 16},
                {name: "binary_cycling_64", typ: PrimitiveTypes.Binary, 
pattern: "cycling", width: 64},
                {name: "binary_monotonic_64", typ: PrimitiveTypes.Binary, 
pattern: "monotonic", width: 64},
-               {name: "fixed_repeated_16", typ: FixedTypeOf(16), pattern: 
"repeated", width: 16},
-               {name: "fixed_cycling_64", typ: FixedTypeOf(64), pattern: 
"cycling", width: 64},
-               {name: "fixed_monotonic_64", typ: FixedTypeOf(64), pattern: 
"monotonic", width: 64},
+               {name: "fixed_repeated_16", typ: MustFixedTypeOf(16), pattern: 
"repeated", width: 16},
+               {name: "fixed_cycling_64", typ: MustFixedTypeOf(64), pattern: 
"cycling", width: 64},
+               {name: "fixed_monotonic_64", typ: MustFixedTypeOf(64), pattern: 
"monotonic", width: 64},
        } {
                values := partitionFieldStatsBenchmarkValues(10_000, tc.width, 
tc.pattern)
 
diff --git a/manifest_test.go b/manifest_test.go
index 41469ccd6..382be1353 100644
--- a/manifest_test.go
+++ b/manifest_test.go
@@ -532,7 +532,7 @@ func TestPartitionFieldStatsAcceptsConvertibleValues(t 
*testing.T) {
                {name: "time from duration", typ: PrimitiveTypes.Time, value: 
time.Duration(11), want: NewLiteral(Time(11))},
                {name: "timestamp from int64", typ: PrimitiveTypes.Timestamp, 
value: int64(12), want: NewLiteral(Timestamp(12))},
                {name: "binary from string", typ: PrimitiveTypes.Binary, value: 
"shard", want: NewLiteral([]byte("shard"))},
-               {name: "fixed from bytes", typ: FixedTypeOf(5), value: "fixed", 
want: NewLiteral([]byte("fixed"))},
+               {name: "fixed from bytes", typ: MustFixedTypeOf(5), value: 
"fixed", want: NewLiteral([]byte("fixed"))},
                {
                        name:  "uuid from array",
                        typ:   PrimitiveTypes.UUID,
@@ -541,7 +541,7 @@ func TestPartitionFieldStatsAcceptsConvertibleValues(t 
*testing.T) {
                },
                {
                        name:  "decimal from decimal literal",
-                       typ:   DecimalTypeOf(10, 2),
+                       typ:   MustDecimalTypeOf(10, 2),
                        value: DecimalLiteral{Val: decimal128.FromI64(130), 
Scale: 2},
                        want:  NewLiteral(Decimal{Val: decimal128.FromI64(130), 
Scale: 2}),
                },
@@ -590,8 +590,8 @@ func TestPartitionFieldStatsRejectsUnsupportedValues(t 
*testing.T) {
                {name: "timestamp with timezone", typ: 
PrimitiveTypes.TimestampTz},
                {name: "uuid", typ: PrimitiveTypes.UUID},
                {name: "binary", typ: PrimitiveTypes.Binary},
-               {name: "fixed", typ: FixedTypeOf(5)},
-               {name: "decimal", typ: DecimalTypeOf(10, 2)},
+               {name: "fixed", typ: MustFixedTypeOf(5)},
+               {name: "decimal", typ: MustDecimalTypeOf(10, 2)},
        }
 
        for _, tt := range tests {
@@ -3202,7 +3202,7 @@ func 
TestAvroEncodePartitionDataUsesDeclaredDecimalFixedSize(t *testing.T) {
 func TestManifestRoundTripDecimalPartitionUsesSignedFixedSize(t *testing.T) {
        schema := NewSchema(
                0,
-               NestedField{ID: 1, Name: "price", Type: DecimalTypeOf(10, 2)},
+               NestedField{ID: 1, Name: "price", Type: MustDecimalTypeOf(10, 
2)},
        )
        partitionSpec := NewPartitionSpecID(
                1,
diff --git a/partitions_test.go b/partitions_test.go
index 274dfe042..a91c48413 100644
--- a/partitions_test.go
+++ b/partitions_test.go
@@ -529,7 +529,7 @@ func TestPartitionTypePreservesFieldOrderAndResultTypes(t 
*testing.T) {
                        {ID: 2, Name: "nested", Type: iceberg.Int64Type{}, 
Required: true},
                }}},
                iceberg.NestedField{ID: 3, Name: "ts", Type: 
iceberg.TimestampTzNsType{}, Required: true},
-               iceberg.NestedField{ID: 4, Name: "amount", Type: 
iceberg.DecimalTypeOf(12, 2)},
+               iceberg.NestedField{ID: 4, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(12, 2)},
        )
        unknown, err := iceberg.ParseTransform("custom_transform[42]")
        require.NoError(t, err)
@@ -549,7 +549,7 @@ func TestPartitionTypePreservesFieldOrderAndResultTypes(t 
*testing.T) {
        want := []iceberg.NestedField{
                {ID: 1007, Name: "nested", Type: iceberg.Int64Type{}},
                {ID: 1001, Name: "ts", Type: iceberg.TimestampTzNsType{}},
-               {ID: 1006, Name: "amount", Type: iceberg.DecimalTypeOf(12, 2)},
+               {ID: 1006, Name: "amount", Type: iceberg.MustDecimalTypeOf(12, 
2)},
                {ID: 1002, Name: "missing_bucket", Type: iceberg.Int32Type{}},
                {ID: 1005, Name: "missing_day", Type: iceberg.DateType{}},
                {ID: 1003, Name: "missing_identity", Type: 
iceberg.UnknownType{}},
diff --git a/schema_compatibility_test.go b/schema_compatibility_test.go
index 6fbde7983..af16e89f1 100644
--- a/schema_compatibility_test.go
+++ b/schema_compatibility_test.go
@@ -55,12 +55,12 @@ func compatPrimitives(t *testing.T) []iceberg.PrimitiveType 
{
                iceberg.PrimitiveTypes.TimestampTzNs,
                iceberg.PrimitiveTypes.String,
                iceberg.PrimitiveTypes.UUID,
-               iceberg.FixedTypeOf(3),
-               iceberg.FixedTypeOf(4),
+               iceberg.MustFixedTypeOf(3),
+               iceberg.MustFixedTypeOf(4),
                iceberg.PrimitiveTypes.Binary,
-               iceberg.DecimalTypeOf(9, 2),
-               iceberg.DecimalTypeOf(11, 2),
-               iceberg.DecimalTypeOf(9, 3),
+               iceberg.MustDecimalTypeOf(9, 2),
+               iceberg.MustDecimalTypeOf(11, 2),
+               iceberg.MustDecimalTypeOf(9, 3),
                geomCRS84,
                geom3857,
                geogCRS84,
@@ -139,11 +139,11 @@ func TestIsPromotionAllowed(t *testing.T) {
                {iceberg.PrimitiveTypes.Int64, iceberg.PrimitiveTypes.Int32, 
false},
                {iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, true},
                {iceberg.PrimitiveTypes.Float64, 
iceberg.PrimitiveTypes.Float32, false},
-               {iceberg.DecimalTypeOf(9, 2), iceberg.DecimalTypeOf(11, 2), 
true},
-               {iceberg.DecimalTypeOf(11, 2), iceberg.DecimalTypeOf(9, 2), 
false},
-               {iceberg.DecimalTypeOf(9, 2), iceberg.DecimalTypeOf(9, 3), 
false},
+               {iceberg.MustDecimalTypeOf(9, 2), iceberg.MustDecimalTypeOf(11, 
2), true},
+               {iceberg.MustDecimalTypeOf(11, 2), iceberg.MustDecimalTypeOf(9, 
2), false},
+               {iceberg.MustDecimalTypeOf(9, 2), iceberg.MustDecimalTypeOf(9, 
3), false},
                {iceberg.PrimitiveTypes.String, iceberg.PrimitiveTypes.Binary, 
false},
-               {iceberg.FixedTypeOf(16), iceberg.PrimitiveTypes.UUID, false},
+               {iceberg.MustFixedTypeOf(16), iceberg.PrimitiveTypes.UUID, 
false},
                {iceberg.PrimitiveTypes.Date, iceberg.PrimitiveTypes.Timestamp, 
false},
        }
 
diff --git a/table/arrow_filter_plan_key_test.go 
b/table/arrow_filter_plan_key_test.go
index 838cc51cb..a3878c605 100644
--- a/table/arrow_filter_plan_key_test.go
+++ b/table/arrow_filter_plan_key_test.go
@@ -42,11 +42,11 @@ func TestPhysicalSchemaKeyDistinctTypeTags(t *testing.T) {
                iceberg.BinaryType{},
                iceberg.UnknownType{},
                iceberg.VariantType{},
-               iceberg.FixedTypeOf(8),
-               iceberg.FixedTypeOf(16),
-               iceberg.DecimalTypeOf(10, 2),
-               iceberg.DecimalTypeOf(11, 2),
-               iceberg.DecimalTypeOf(10, 3),
+               iceberg.MustFixedTypeOf(8),
+               iceberg.MustFixedTypeOf(16),
+               iceberg.MustDecimalTypeOf(10, 2),
+               iceberg.MustDecimalTypeOf(11, 2),
+               iceberg.MustDecimalTypeOf(10, 3),
        }
        keys := make(map[string]string, len(types))
        for _, typ := range types {
diff --git a/table/arrow_filter_plan_test.go b/table/arrow_filter_plan_test.go
index c96e726de..a33290d24 100644
--- a/table/arrow_filter_plan_test.go
+++ b/table/arrow_filter_plan_test.go
@@ -236,9 +236,9 @@ func TestPhysicalSchemaKeyDistinguishesNestedLayouts(t 
*testing.T) {
                        }},
                        {ID: 4, Name: "lookup", Type: &iceberg.MapType{
                                KeyID: 5, KeyType: 
iceberg.PrimitiveTypes.String,
-                               ValueID: 6, ValueType: 
iceberg.DecimalTypeOf(10, 2),
+                               ValueID: 6, ValueType: 
iceberg.MustDecimalTypeOf(10, 2),
                        }},
-                       {ID: 7, Name: "fixed", Type: iceberg.FixedTypeOf(8)},
+                       {ID: 7, Name: "fixed", Type: 
iceberg.MustFixedTypeOf(8)},
                        {ID: 8, Name: "variant", Type: iceberg.VariantType{}},
                }},
        })
@@ -265,12 +265,12 @@ func TestPhysicalSchemaKeyDistinguishesNestedLayouts(t 
*testing.T) {
                {"map_value_id", func(s *iceberg.StructType) { 
s.FieldList[1].Type.(*iceberg.MapType).ValueID = 60 }},
                {"map_value_required", func(s *iceberg.StructType) { 
s.FieldList[1].Type.(*iceberg.MapType).ValueRequired = true }},
                {"decimal_precision", func(s *iceberg.StructType) {
-                       s.FieldList[1].Type.(*iceberg.MapType).ValueType = 
iceberg.DecimalTypeOf(11, 2)
+                       s.FieldList[1].Type.(*iceberg.MapType).ValueType = 
iceberg.MustDecimalTypeOf(11, 2)
                }},
                {"decimal_scale", func(s *iceberg.StructType) {
-                       s.FieldList[1].Type.(*iceberg.MapType).ValueType = 
iceberg.DecimalTypeOf(10, 3)
+                       s.FieldList[1].Type.(*iceberg.MapType).ValueType = 
iceberg.MustDecimalTypeOf(10, 3)
                }},
-               {"fixed_size", func(s *iceberg.StructType) { 
s.FieldList[2].Type = iceberg.FixedTypeOf(16) }},
+               {"fixed_size", func(s *iceberg.StructType) { 
s.FieldList[2].Type = iceberg.MustFixedTypeOf(16) }},
                {"variant_type", func(s *iceberg.StructType) { 
s.FieldList[3].Type = iceberg.PrimitiveTypes.Binary }},
                {"empty_struct", func(s *iceberg.StructType) { s.FieldList = 
nil }},
        } {
diff --git a/table/arrow_scanner_bench_test.go 
b/table/arrow_scanner_bench_test.go
index f0cdeff7b..5a945d7ea 100644
--- a/table/arrow_scanner_bench_test.go
+++ b/table/arrow_scanner_bench_test.go
@@ -512,8 +512,8 @@ func benchmarkPhysicalSchemaCases() []struct {
                {ID: 1, Name: "flag", Type: iceberg.PrimitiveTypes.Bool},
                {ID: 2, Name: "count", Type: iceberg.PrimitiveTypes.Int32},
                {ID: 3, Name: "ratio", Type: iceberg.PrimitiveTypes.Float64},
-               {ID: 4, Name: "fixed", Type: iceberg.FixedTypeOf(16)},
-               {ID: 5, Name: "price", Type: iceberg.DecimalTypeOf(20, 4)},
+               {ID: 4, Name: "fixed", Type: iceberg.MustFixedTypeOf(16)},
+               {ID: 5, Name: "price", Type: iceberg.MustDecimalTypeOf(20, 4)},
                {ID: 6, Name: "created", Type: 
iceberg.PrimitiveTypes.TimestampTzNs},
                {ID: 7, Name: "payload", Type: iceberg.VariantType{}},
                {ID: 8, Name: "tags", Type: &iceberg.ListType{
diff --git a/table/arrow_utils.go b/table/arrow_utils.go
index b76cbd017..1cc15095e 100644
--- a/table/arrow_utils.go
+++ b/table/arrow_utils.go
@@ -393,7 +393,7 @@ func (c convertToIceberg) Primitive(dt arrow.DataType) 
(result iceberg.NestedFie
                result.Type = iceberg.PrimitiveTypes.Float64
        case *arrow.Decimal32Type, *arrow.Decimal64Type, *arrow.Decimal128Type:
                dec := dt.(arrow.DecimalType)
-               result.Type = iceberg.DecimalTypeOf(int(dec.GetPrecision()), 
int(dec.GetScale()))
+               result.Type = 
iceberg.MustDecimalTypeOf(int(dec.GetPrecision()), int(dec.GetScale()))
        case *arrow.StringType, *arrow.LargeStringType:
                result.Type = iceberg.PrimitiveTypes.String
        case *arrow.BinaryType, *arrow.LargeBinaryType:
@@ -431,7 +431,7 @@ func (c convertToIceberg) Primitive(dt arrow.DataType) 
(result iceberg.NestedFie
                        panic(fmt.Errorf("%w: unsupported arrow type for 
conversion - %s", iceberg.ErrInvalidSchema, dt))
                }
        case *arrow.FixedSizeBinaryType:
-               result.Type = iceberg.FixedTypeOf(dt.ByteWidth)
+               result.Type = iceberg.MustFixedTypeOf(dt.ByteWidth)
        case arrow.ExtensionType:
                switch dt.ExtensionName() {
                case "arrow.uuid":
diff --git a/table/arrow_utils_test.go b/table/arrow_utils_test.go
index 621d963ad..34be5b0d4 100644
--- a/table/arrow_utils_test.go
+++ b/table/arrow_utils_test.go
@@ -59,12 +59,12 @@ func TestArrowToIceberg(t *testing.T) {
                reciprocal bool
                err        string
        }{
-               {&arrow.FixedSizeBinaryType{ByteWidth: 0}, 
iceberg.FixedTypeOf(0), true, ""},
-               {&arrow.FixedSizeBinaryType{ByteWidth: 23}, 
iceberg.FixedTypeOf(23), true, ""},
-               {&arrow.Decimal32Type{Precision: 8, Scale: 2}, 
iceberg.DecimalTypeOf(8, 2), false, ""},
+               {&arrow.FixedSizeBinaryType{ByteWidth: 0}, 
iceberg.MustFixedTypeOf(0), true, ""},
+               {&arrow.FixedSizeBinaryType{ByteWidth: 23}, 
iceberg.MustFixedTypeOf(23), true, ""},
+               {&arrow.Decimal32Type{Precision: 8, Scale: 2}, 
iceberg.MustDecimalTypeOf(8, 2), false, ""},
                {&arrow.Decimal32Type{Precision: 8, Scale: 9}, nil, false, 
"invalid scale 9: must be less than or equal to precision 8"},
-               {&arrow.Decimal64Type{Precision: 15, Scale: 14}, 
iceberg.DecimalTypeOf(15, 14), false, ""},
-               {&arrow.Decimal128Type{Precision: 26, Scale: 20}, 
iceberg.DecimalTypeOf(26, 20), true, ""},
+               {&arrow.Decimal64Type{Precision: 15, Scale: 14}, 
iceberg.MustDecimalTypeOf(15, 14), false, ""},
+               {&arrow.Decimal128Type{Precision: 26, Scale: 20}, 
iceberg.MustDecimalTypeOf(26, 20), true, ""},
                {&arrow.Decimal256Type{Precision: 8, Scale: 9}, nil, false, 
"unsupported arrow type for conversion - decimal256(8, 9)"},
                {arrow.FixedWidthTypes.Boolean, iceberg.PrimitiveTypes.Bool, 
true, ""},
                {arrow.Null, iceberg.PrimitiveTypes.Unknown, true, ""},
@@ -1830,7 +1830,7 @@ func TestToRequestedSchemaWriteDefaultsTypes(t 
*testing.T) {
                {
                        name: "decimal write-default",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "price", Type: 
iceberg.DecimalTypeOf(10, 2),
+                               ID: 2, Name: "price", Type: 
iceberg.MustDecimalTypeOf(10, 2),
                                Required: false, WriteDefault: 
iceberg.Decimal{Val: decimal128.New(0, 12345), Scale: 2},
                        },
                        check: func(t *testing.T, col arrow.Array) {
@@ -2059,7 +2059,7 @@ func TestToRequestedSchemaInitialDefaultTypes(t 
*testing.T) {
                {
                        name: "decimal initial-default",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "price", Type: 
iceberg.DecimalTypeOf(10, 2),
+                               ID: 2, Name: "price", Type: 
iceberg.MustDecimalTypeOf(10, 2),
                                Required: false, InitialDefault: 
iceberg.Decimal{Val: decimal128.New(0, 12345), Scale: 2},
                        },
                        check: func(t *testing.T, col arrow.Array) {
diff --git a/table/equality_delete_index_metrics_test.go 
b/table/equality_delete_index_metrics_test.go
index 757236c3a..4a388c2d7 100644
--- a/table/equality_delete_index_metrics_test.go
+++ b/table/equality_delete_index_metrics_test.go
@@ -340,13 +340,13 @@ func 
TestEqualityDeleteIndexDoesNotUseUncertainFloatBounds(t *testing.T) {
 }
 
 func TestEqualityDeleteMetricValueCompareSupportsRangeTypes(t *testing.T) {
-       decimalLower, err := iceberg.LiteralFromBytes(iceberg.DecimalTypeOf(9, 
0), []byte{1})
+       decimalLower, err := 
iceberg.LiteralFromBytes(iceberg.MustDecimalTypeOf(9, 0), []byte{1})
        require.NoError(t, err)
-       decimalUpper, err := iceberg.LiteralFromBytes(iceberg.DecimalTypeOf(9, 
0), []byte{2})
+       decimalUpper, err := 
iceberg.LiteralFromBytes(iceberg.MustDecimalTypeOf(9, 0), []byte{2})
        require.NoError(t, err)
-       fixedLower, err := iceberg.LiteralFromBytes(iceberg.FixedTypeOf(2), 
[]byte{1, 0})
+       fixedLower, err := iceberg.LiteralFromBytes(iceberg.MustFixedTypeOf(2), 
[]byte{1, 0})
        require.NoError(t, err)
-       fixedUpper, err := iceberg.LiteralFromBytes(iceberg.FixedTypeOf(2), 
[]byte{2, 0})
+       fixedUpper, err := iceberg.LiteralFromBytes(iceberg.MustFixedTypeOf(2), 
[]byte{2, 0})
        require.NoError(t, err)
 
        tests := []struct {
@@ -366,13 +366,13 @@ func 
TestEqualityDeleteMetricValueCompareSupportsRangeTypes(t *testing.T) {
                {"timestamp-nano", iceberg.PrimitiveTypes.TimestampNs, 
iceberg.NewLiteral(iceberg.TimestampNano(1)), 
iceberg.NewLiteral(iceberg.TimestampNano(2))},
                {"string", iceberg.PrimitiveTypes.String, 
iceberg.NewLiteral("a"), iceberg.NewLiteral("b")},
                {"binary", iceberg.PrimitiveTypes.Binary, 
iceberg.NewLiteral([]byte{1}), iceberg.NewLiteral([]byte{2})},
-               {"fixed", iceberg.FixedTypeOf(2), fixedLower, fixedUpper},
+               {"fixed", iceberg.MustFixedTypeOf(2), fixedLower, fixedUpper},
                {
                        "uuid", iceberg.PrimitiveTypes.UUID,
                        
iceberg.NewLiteral(uuid.MustParse("00000000-0000-0000-0000-000000000001")),
                        
iceberg.NewLiteral(uuid.MustParse("00000000-0000-0000-0000-000000000002")),
                },
-               {"decimal", iceberg.DecimalTypeOf(9, 0), decimalLower, 
decimalUpper},
+               {"decimal", iceberg.MustDecimalTypeOf(9, 0), decimalLower, 
decimalUpper},
        }
 
        for _, tt := range tests {
diff --git a/table/equality_delete_writer_test.go 
b/table/equality_delete_writer_test.go
index 436cfcb1a..8db449fa3 100644
--- a/table/equality_delete_writer_test.go
+++ b/table/equality_delete_writer_test.go
@@ -354,7 +354,7 @@ func newPartitionedEqDeleteTestTable(t *testing.T) 
*table.Table {
                iceberg.NestedField{ID: 1, Name: "id", Type: 
iceberg.PrimitiveTypes.Int64, Required: true},
                iceberg.NestedField{ID: 2, Name: "category", Type: 
iceberg.PrimitiveTypes.String, Required: true},
                iceberg.NestedField{ID: 3, Name: "score", Type: 
iceberg.PrimitiveTypes.Float32, Required: false},
-               iceberg.NestedField{ID: 4, Name: "price", Type: 
iceberg.DecimalTypeOf(10, 2), Required: false},
+               iceberg.NestedField{ID: 4, Name: "price", Type: 
iceberg.MustDecimalTypeOf(10, 2), Required: false},
        )
 
        partSpec := iceberg.NewPartitionSpec(
@@ -447,7 +447,7 @@ func 
TestWriteEqualityDeleteFilesPartitionedTableAcceptsDecimalFieldID(t *testin
        tbl := newPartitionedEqDeleteTestTable(t)
 
        delSchema := iceberg.NewSchema(0,
-               iceberg.NestedField{ID: 4, Name: "price", Type: 
iceberg.DecimalTypeOf(10, 2), Required: false},
+               iceberg.NestedField{ID: 4, Name: "price", Type: 
iceberg.MustDecimalTypeOf(10, 2), Required: false},
                iceberg.NestedField{ID: 2, Name: "category", Type: 
iceberg.PrimitiveTypes.String, Required: true},
        )
        delArrowSc, err := table.SchemaToArrowSchema(delSchema, nil, true, 
false)
diff --git a/table/evaluators_invalid_bounds_test.go 
b/table/evaluators_invalid_bounds_test.go
index a79d01d46..93ea9c02f 100644
--- a/table/evaluators_invalid_bounds_test.go
+++ b/table/evaluators_invalid_bounds_test.go
@@ -26,7 +26,7 @@ import (
 
 func TestMalformedFixedBoundsAreConservative(t *testing.T) {
        schema := iceberg.NewSchema(1, iceberg.NestedField{
-               ID: 1, Name: "value", Type: iceberg.FixedTypeOf(4),
+               ID: 1, Name: "value", Type: iceberg.MustFixedTypeOf(4),
        })
        expr := iceberg.EqualTo(iceberg.Reference("value"), []byte{1, 2, 3, 4})
        malformed := []byte{1, 2, 3, 4, 5}
diff --git a/table/evaluators_row_group_test.go 
b/table/evaluators_row_group_test.go
index 3ede72b98..a010b976c 100644
--- a/table/evaluators_row_group_test.go
+++ b/table/evaluators_row_group_test.go
@@ -209,7 +209,7 @@ func TestInclusiveMetricsEvalIntBackedDecimalRowGroup(t 
*testing.T) {
                                minUnscaled, maxUnscaled := rng.minUnscaled, 
rng.maxUnscaled
                                meta := buildDecimalRowGroupMetadata(t, 
tt.physical, tt.typeLen,
                                        int32(tt.precision), scale, 
tt.encode(minUnscaled), tt.encode(maxUnscaled))
-                               field := iceberg.DecimalTypeOf(tt.precision, 
scale)
+                               field := 
iceberg.MustDecimalTypeOf(tt.precision, scale)
                                ref := iceberg.Reference("decimal")
 
                                keep := func(pred iceberg.BooleanExpression) 
bool {
@@ -288,7 +288,7 @@ func TestInclusiveMetricsEvalRealParquetDecimalRowGroup(t 
*testing.T) {
        require.True(t, intBackedDecimal(stats.Descr()),
                "writer did not produce an INT32-backed decimal, so this test 
no longer covers the bug")
 
-       field := iceberg.DecimalTypeOf(precision, scale)
+       field := iceberg.MustDecimalTypeOf(precision, scale)
        ref := iceberg.Reference("decimal")
        schema := iceberg.NewSchema(0, iceberg.NestedField{
                ID: 1, Name: "decimal", Type: field, Required: true,
diff --git a/table/in_predicate_extrema_bench_test.go 
b/table/in_predicate_extrema_bench_test.go
index 0cfe2da9d..293269b74 100644
--- a/table/in_predicate_extrema_bench_test.go
+++ b/table/in_predicate_extrema_bench_test.go
@@ -71,13 +71,13 @@ func BenchmarkManifestEvaluatorInPredicate(b *testing.B) {
                        }
 
                        b.Run("pruned-lower", func(b *testing.B) {
-                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(int64(literalCount+1) * 100), Scale: 
2}, iceberg.Decimal{Val: decimal128.FromI64(int64(literalCount+1) * 100), 
Scale: 2}, iceberg.DecimalTypeOf(12, 2))
+                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(int64(literalCount+1) * 100), Scale: 
2}, iceberg.Decimal{Val: decimal128.FromI64(int64(literalCount+1) * 100), 
Scale: 2}, iceberg.MustDecimalTypeOf(12, 2))
                        })
                        b.Run("pruned-upper", func(b *testing.B) {
-                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(-100), Scale: 2}, iceberg.Decimal{Val: 
decimal128.FromI64(-100), Scale: 2}, iceberg.DecimalTypeOf(12, 2))
+                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(-100), Scale: 2}, iceberg.Decimal{Val: 
decimal128.FromI64(-100), Scale: 2}, iceberg.MustDecimalTypeOf(12, 2))
                        })
                        b.Run("no-prune", func(b *testing.B) {
-                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(-100), Scale: 2}, iceberg.Decimal{Val: 
decimal128.FromI64(int64(literalCount+1) * 100), Scale: 2}, 
iceberg.DecimalTypeOf(12, 2))
+                               benchmarkManifestIn(b, values, 
iceberg.Decimal{Val: decimal128.FromI64(-100), Scale: 2}, iceberg.Decimal{Val: 
decimal128.FromI64(int64(literalCount+1) * 100), Scale: 2}, 
iceberg.MustDecimalTypeOf(12, 2))
                        })
                })
        }
@@ -132,7 +132,7 @@ func BenchmarkInclusiveMetricsEvalInPredicate(b *testing.B) 
{
                                // Keep lexical and numeric order identical, 
including the below-set bound.
                                return 
iceberg.NewLiteral(fmt.Sprintf("value-%06d", value+1000))
                        }},
-                       {"decimal", iceberg.DecimalTypeOf(12, 2), func(value 
int) iceberg.Literal {
+                       {"decimal", iceberg.MustDecimalTypeOf(12, 2), 
func(value int) iceberg.Literal {
                                return iceberg.NewLiteral(iceberg.Decimal{Val: 
decimal128.FromI64(int64(value)), Scale: 2})
                        }},
                } {
diff --git a/table/in_predicate_extrema_test.go 
b/table/in_predicate_extrema_test.go
index 59397deaf..04b135dc8 100644
--- a/table/in_predicate_extrema_test.go
+++ b/table/in_predicate_extrema_test.go
@@ -85,7 +85,7 @@ func TestManifestEvaluatorInPredicateExtrema(t *testing.T) {
        tests := []testCase{
                {
                        name:       "decimal below lower bound",
-                       typ:        iceberg.DecimalTypeOf(12, 2),
+                       typ:        iceberg.MustDecimalTypeOf(12, 2),
                        expr:       iceberg.IsIn(iceberg.Reference("value"), 
decimal(100), decimal(200), decimal(300)),
                        lower:      iceberg.NewLiteral(decimal(400)),
                        upper:      iceberg.NewLiteral(decimal(500)),
@@ -93,7 +93,7 @@ func TestManifestEvaluatorInPredicateExtrema(t *testing.T) {
                },
                {
                        name:       "decimal above upper bound",
-                       typ:        iceberg.DecimalTypeOf(12, 2),
+                       typ:        iceberg.MustDecimalTypeOf(12, 2),
                        expr:       iceberg.IsIn(iceberg.Reference("value"), 
decimal(100), decimal(200), decimal(300)),
                        lower:      iceberg.NewLiteral(decimal(-100)),
                        upper:      iceberg.NewLiteral(decimal(0)),
@@ -101,7 +101,7 @@ func TestManifestEvaluatorInPredicateExtrema(t *testing.T) {
                },
                {
                        name:       "decimal overlaps bound",
-                       typ:        iceberg.DecimalTypeOf(12, 2),
+                       typ:        iceberg.MustDecimalTypeOf(12, 2),
                        expr:       iceberg.IsIn(iceberg.Reference("value"), 
decimal(100), decimal(200), decimal(300)),
                        lower:      iceberg.NewLiteral(decimal(200)),
                        upper:      iceberg.NewLiteral(decimal(250)),
@@ -328,14 +328,14 @@ func 
TestInclusiveMetricsEvaluatorInPredicateExtremaFastPathTypes(t *testing.T)
                },
                {
                        name:   "decimal upper disjoint",
-                       typ:    iceberg.DecimalTypeOf(12, 2),
+                       typ:    iceberg.MustDecimalTypeOf(12, 2),
                        expr:   iceberg.IsIn(iceberg.Reference("value"), 
decimal(100), decimal(200)),
                        minLit: iceberg.NewLiteral(decimal(100)), maxLit: 
iceberg.NewLiteral(decimal(200)),
                        lower: iceberg.NewLiteral(decimal(-200)), upper: 
iceberg.NewLiteral(decimal(0)),
                },
                {
                        name:   "decimal overlaps",
-                       typ:    iceberg.DecimalTypeOf(12, 2),
+                       typ:    iceberg.MustDecimalTypeOf(12, 2),
                        expr:   iceberg.IsIn(iceberg.Reference("value"), 
decimal(100), decimal(200)),
                        minLit: iceberg.NewLiteral(decimal(100)), maxLit: 
iceberg.NewLiteral(decimal(200)),
                        lower: iceberg.NewLiteral(decimal(100)), upper: 
iceberg.NewLiteral(decimal(150)),
@@ -456,7 +456,7 @@ func 
TestInclusiveMetricsEvaluatorInPredicateExtremaUsesFastPath(t *testing.T) {
                        iceberg.NewLiteral("a"), iceberg.NewLiteral("b"),
                },
                {
-                       "decimal", iceberg.DecimalTypeOf(12, 2),
+                       "decimal", iceberg.MustDecimalTypeOf(12, 2),
                        []iceberg.Literal{iceberg.NewLiteral(decimal(5000)), 
iceberg.NewLiteral(decimal(6000))},
                        iceberg.NewLiteral(decimal(100)), 
iceberg.NewLiteral(decimal(200)),
                },
diff --git a/table/inspect_internal_test.go b/table/inspect_internal_test.go
index 1b26c60e3..fd91c12bf 100644
--- a/table/inspect_internal_test.go
+++ b/table/inspect_internal_test.go
@@ -3326,7 +3326,7 @@ func 
TestInspectPositionDeletesParquetProjectsEvolvedNestedRow(t *testing.T) {
        tableSchema := iceberg.NewSchema(0,
                iceberg.NestedField{ID: 1, Name: "values", Type: tableListType, 
Required: true},
                iceberg.NestedField{ID: 2, Name: "attributes", Type: 
tableMapType, Required: true},
-               iceberg.NestedField{ID: 6, Name: "amount", Type: 
iceberg.DecimalTypeOf(18, 2), Required: true},
+               iceberg.NestedField{ID: 6, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(18, 2), Required: true},
        )
 
        sourceListType := arrow.ListOfField(arrow.Field{
@@ -3846,7 +3846,7 @@ func 
TestPositionDeleteRowProjectionPromotesNestedValues(t *testing.T) {
        tableSchema := iceberg.NewSchema(0,
                iceberg.NestedField{ID: 1, Name: "values", Type: tableListType, 
Required: true},
                iceberg.NestedField{ID: 2, Name: "attributes", Type: 
tableMapType, Required: true},
-               iceberg.NestedField{ID: 6, Name: "amount", Type: 
iceberg.DecimalTypeOf(18, 2), Required: true},
+               iceberg.NestedField{ID: 6, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(18, 2), Required: true},
        )
        outputSchema, err := SchemaToArrowSchema(
                PositionDeletesSchema(tableSchema, &iceberg.StructType{}, 2), 
nil, true, false)
@@ -4269,7 +4269,7 @@ func testFieldNames(sc *iceberg.Schema) []string {
 }
 
 func TestInspectValueScalarDecimal(t *testing.T) {
-       typ := iceberg.DecimalTypeOf(10, 2)
+       typ := iceberg.MustDecimalTypeOf(10, 2)
        arrowType := &arrow.Decimal128Type{Precision: 10, Scale: 2}
        value := iceberg.DecimalLiteral{Val: decimal128.FromI64(123), Scale: 2}
 
diff --git a/table/inspect_partition_append_test.go 
b/table/inspect_partition_append_test.go
index 1706f3431..0ecab8502 100644
--- a/table/inspect_partition_append_test.go
+++ b/table/inspect_partition_append_test.go
@@ -126,7 +126,7 @@ func 
TestInspectPartitionBuilderAppendsTypedAndFallbackValues(t *testing.T) {
                },
                {
                        name:  "decimal scalar fallback",
-                       typ:   iceberg.DecimalTypeOf(10, 2),
+                       typ:   iceberg.MustDecimalTypeOf(10, 2),
                        value: iceberg.DecimalLiteral{Val: 
decimal128.FromI64(123), Scale: 2},
                        check: func(t *testing.T, value arrow.Array) {
                                require.Equal(t, decimal128.FromI64(123), 
value.(*array.Decimal128).Value(0))
@@ -134,7 +134,7 @@ func 
TestInspectPartitionBuilderAppendsTypedAndFallbackValues(t *testing.T) {
                },
                {
                        name:  "fixed scalar fallback",
-                       typ:   iceberg.FixedTypeOf(3),
+                       typ:   iceberg.MustFixedTypeOf(3),
                        value: []byte("abc"),
                        check: func(t *testing.T, value arrow.Array) {
                                require.Equal(t, []byte("abc"), 
value.(*array.FixedSizeBinary).Value(0))
@@ -181,7 +181,7 @@ func 
TestInspectPartitionBuilderScalarFallbackPreservesValidation(t *testing.T)
                {name: "compatible integer string", typ: 
iceberg.PrimitiveTypes.Int32, value: "42"},
                {name: "invalid integer string", typ: 
iceberg.PrimitiveTypes.Int32, value: "not-an-int", wantErr: "partition field 
\"value\": strconv.ParseInt"},
                {name: "wrong date value", typ: iceberg.PrimitiveTypes.Date, 
value: int64(1), wantErr: "partition field \"value\": unsupported date"},
-               {name: "wrong fixed width", typ: iceberg.FixedTypeOf(2), value: 
[]byte("x"), wantErr: "invalid scalar value of len"},
+               {name: "wrong fixed width", typ: iceberg.MustFixedTypeOf(2), 
value: []byte("x"), wantErr: "invalid scalar value of len"},
        }
 
        for _, tt := range tests {
diff --git a/table/internal/parquet_files_test.go 
b/table/internal/parquet_files_test.go
index 5effcffdf..e98a4703e 100644
--- a/table/internal/parquet_files_test.go
+++ b/table/internal/parquet_files_test.go
@@ -467,19 +467,19 @@ func getCollector() map[int]internal.StatisticsCollector {
                        FieldID:    13,
                        Mode:       modeFull,
                        ColName:    "small_dec",
-                       IcebergTyp: iceberg.DecimalTypeOf(8, 2),
+                       IcebergTyp: iceberg.MustDecimalTypeOf(8, 2),
                },
                14: {
                        FieldID:    14,
                        Mode:       modeFull,
                        ColName:    "med_dec",
-                       IcebergTyp: iceberg.DecimalTypeOf(16, 2),
+                       IcebergTyp: iceberg.MustDecimalTypeOf(16, 2),
                },
                15: {
                        FieldID:    15,
                        Mode:       modeFull,
                        ColName:    "large_dec",
-                       IcebergTyp: iceberg.DecimalTypeOf(24, 2),
+                       IcebergTyp: iceberg.MustDecimalTypeOf(24, 2),
                },
        }
 }
@@ -588,16 +588,16 @@ func TestMetricsPrimitiveTypes(t *testing.T) {
        assertBounds(t, df.LowerBoundValues()[11], iceberg.PrimitiveTypes.UUID,
                uuid.NewMD5(uuid.NameSpaceDNS, []byte("foo")))
        assertBounds(t, df.LowerBoundValues()[12], 
iceberg.PrimitiveTypes.Binary, []byte("he"))
-       assertBounds(t, df.LowerBoundValues()[13], iceberg.DecimalTypeOf(8, 2), 
iceberg.Decimal{
+       assertBounds(t, df.LowerBoundValues()[13], iceberg.MustDecimalTypeOf(8, 
2), iceberg.Decimal{
                Val:   decimal128.FromI64(12345678),
                Scale: 2,
        })
-       assertBounds(t, df.LowerBoundValues()[14], iceberg.DecimalTypeOf(16, 
2), iceberg.Decimal{
+       assertBounds(t, df.LowerBoundValues()[14], 
iceberg.MustDecimalTypeOf(16, 2), iceberg.Decimal{
                Val:   decimal128.FromI64(1234567890123456),
                Scale: 2,
        })
        expected, _ := (&big.Int{}).SetString("123456789012345678901234", 10)
-       assertBounds(t, df.LowerBoundValues()[15], iceberg.DecimalTypeOf(24, 
2), iceberg.Decimal{
+       assertBounds(t, df.LowerBoundValues()[15], 
iceberg.MustDecimalTypeOf(24, 2), iceberg.Decimal{
                Val:   decimal128.FromBigInt(expected),
                Scale: 2,
        })
@@ -620,16 +620,16 @@ func TestMetricsPrimitiveTypes(t *testing.T) {
        assertBounds(t, df.UpperBoundValues()[11], iceberg.PrimitiveTypes.UUID,
                uuid.NewMD5(uuid.NameSpaceDNS, []byte("bar")))
        assertBounds(t, df.UpperBoundValues()[12], 
iceberg.PrimitiveTypes.Binary, []byte("wp"))
-       assertBounds(t, df.UpperBoundValues()[13], iceberg.DecimalTypeOf(8, 2), 
iceberg.Decimal{
+       assertBounds(t, df.UpperBoundValues()[13], iceberg.MustDecimalTypeOf(8, 
2), iceberg.Decimal{
                Val:   decimal128.FromI64(87654321),
                Scale: 2,
        })
-       assertBounds(t, df.UpperBoundValues()[14], iceberg.DecimalTypeOf(16, 
2), iceberg.Decimal{
+       assertBounds(t, df.UpperBoundValues()[14], 
iceberg.MustDecimalTypeOf(16, 2), iceberg.Decimal{
                Val:   decimal128.FromI64(6543210987654321),
                Scale: 2,
        })
        expectedUpper, _ := (&big.Int{}).SetString("432109876543210987654321", 
10)
-       assertBounds(t, df.UpperBoundValues()[15], iceberg.DecimalTypeOf(24, 
2), iceberg.Decimal{
+       assertBounds(t, df.UpperBoundValues()[15], 
iceberg.MustDecimalTypeOf(24, 2), iceberg.Decimal{
                Val:   decimal128.FromBigInt(expectedUpper),
                Scale: 2,
        })
@@ -1009,7 +1009,7 @@ func TestDecimalPhysicalTypes(t *testing.T) {
                                        FieldID:    1,
                                        Mode:       internal.MetricsMode{Typ: 
internal.MetricModeFull},
                                        ColName:    "value",
-                                       IcebergTyp: 
iceberg.DecimalTypeOf(tt.precision, tt.scale),
+                                       IcebergTyp: 
iceberg.MustDecimalTypeOf(tt.precision, tt.scale),
                                },
                        }
 
@@ -1031,13 +1031,13 @@ func TestDecimalPhysicalTypes(t *testing.T) {
                        require.Contains(t, df.UpperBoundValues(), 1)
 
                        // Verify the actual values
-                       minLit, err := 
iceberg.LiteralFromBytes(iceberg.DecimalTypeOf(tt.precision, tt.scale), 
df.LowerBoundValues()[1])
+                       minLit, err := 
iceberg.LiteralFromBytes(iceberg.MustDecimalTypeOf(tt.precision, tt.scale), 
df.LowerBoundValues()[1])
                        require.NoError(t, err)
                        minDec := 
minLit.(iceberg.TypedLiteral[iceberg.Decimal]).Value()
                        assert.Equal(t, uint64(tt.expectedMin), 
minDec.Val.LowBits())
                        assert.Equal(t, tt.scale, minDec.Scale)
 
-                       maxLit, err := 
iceberg.LiteralFromBytes(iceberg.DecimalTypeOf(tt.precision, tt.scale), 
df.UpperBoundValues()[1])
+                       maxLit, err := 
iceberg.LiteralFromBytes(iceberg.MustDecimalTypeOf(tt.precision, tt.scale), 
df.UpperBoundValues()[1])
                        require.NoError(t, err)
                        maxDec := 
maxLit.(iceberg.TypedLiteral[iceberg.Decimal]).Value()
                        assert.Equal(t, uint64(tt.expectedMax), 
maxDec.Val.LowBits())
diff --git a/table/internal/utils_test.go b/table/internal/utils_test.go
index bb41dbe49..61ae2fd64 100644
--- a/table/internal/utils_test.go
+++ b/table/internal/utils_test.go
@@ -388,7 +388,7 @@ func 
TestDataFileStatisticsDecimalPartitionManifestRoundTrip(t *testing.T) {
        schema := iceberg.NewSchema(1, iceberg.NestedField{
                ID:   1,
                Name: "price",
-               Type: iceberg.DecimalTypeOf(10, 2),
+               Type: iceberg.MustDecimalTypeOf(10, 2),
        })
        spec := iceberg.NewPartitionSpecID(1, iceberg.PartitionField{
                SourceIDs: []int{1},
diff --git a/table/internal/variant_bounds.go b/table/internal/variant_bounds.go
index 21e74463c..f36d3cca0 100644
--- a/table/internal/variant_bounds.go
+++ b/table/internal/variant_bounds.go
@@ -136,7 +136,12 @@ func arrowLeafToIceberg(dt arrow.DataType) 
(iceberg.PrimitiveType, bool) {
                        return iceberg.PrimitiveTypes.TimestampTzNs, true
                }
        case *arrow.Decimal128Type:
-               return iceberg.DecimalTypeOf(int(t.Precision), int(t.Scale)), 
true
+               dec, err := iceberg.DecimalTypeOf(int(t.Precision), 
int(t.Scale))
+               if err != nil {
+                       return nil, false
+               }
+
+               return dec, true
        case arrow.ExtensionType:
                if t.ExtensionName() == "arrow.uuid" {
                        return iceberg.PrimitiveTypes.UUID, true
diff --git a/table/internal/variant_bounds_test.go 
b/table/internal/variant_bounds_test.go
index d7b5d008a..9a84577ae 100644
--- a/table/internal/variant_bounds_test.go
+++ b/table/internal/variant_bounds_test.go
@@ -532,3 +532,29 @@ func TestVariantBoundLiteralMalformed(t *testing.T) {
                assert.False(t, ok, "malformed bytes yield no usable bound")
        }
 }
+
+func TestArrowLeafToIcebergRejectsInvalidDecimal(t *testing.T) {
+       for _, tc := range []struct {
+               name      string
+               precision int32
+               scale     int32
+               valid     bool
+       }{
+               {"valid", 10, 2, true},
+               {"zero precision", 0, 0, false},
+               {"too large precision", 39, 0, false},
+               {"negative scale", 10, -1, false},
+               {"scale above precision", 5, 6, false},
+       } {
+               t.Run(tc.name, func(t *testing.T) {
+                       typ, ok := arrowLeafToIceberg(&arrow.Decimal128Type{
+                               Precision: tc.precision,
+                               Scale:     tc.scale,
+                       })
+                       assert.Equal(t, tc.valid, ok)
+                       if !tc.valid {
+                               assert.Nil(t, typ)
+                       }
+               })
+       }
+}
diff --git a/table/metadata_internal_test.go b/table/metadata_internal_test.go
index 522dd0eb6..ae6206eba 100644
--- a/table/metadata_internal_test.go
+++ b/table/metadata_internal_test.go
@@ -2250,7 +2250,7 @@ func TestTableDataV2NoSnapshots(t *testing.T) {
             "default-sort-order-id": 0
         }`
        schema := iceberg.NewSchema(1, iceberg.NestedField{
-               Type:     iceberg.FixedTypeOf(1),
+               Type:     iceberg.MustFixedTypeOf(1),
                ID:       1,
                Name:     "struct_name",
                Required: true,
diff --git a/table/partition_residual_test.go b/table/partition_residual_test.go
index ed0f74708..84fd71f04 100644
--- a/table/partition_residual_test.go
+++ b/table/partition_residual_test.go
@@ -82,7 +82,7 @@ func 
TestPartitionResidualEvaluatorElidesSatisfiedIdentityPredicate(t *testing.T
 
 func TestPartitionResidualEvaluatorNormalizesDecodedLiteralValues(t 
*testing.T) {
        schema := iceberg.NewSchema(1, iceberg.NestedField{
-               ID: 1, Name: "price", Type: iceberg.DecimalTypeOf(10, 2),
+               ID: 1, Name: "price", Type: iceberg.MustDecimalTypeOf(10, 2),
        })
        spec := iceberg.NewPartitionSpec(iceberg.PartitionField{
                SourceIDs: []int{1}, FieldID: 1000, Name: "price", Transform: 
iceberg.IdentityTransform{},
diff --git a/table/partitioned_fanout_writer_review_test.go 
b/table/partitioned_fanout_writer_review_test.go
index 61c08a3d3..1a3ed000a 100644
--- a/table/partitioned_fanout_writer_review_test.go
+++ b/table/partitioned_fanout_writer_review_test.go
@@ -32,7 +32,7 @@ func (s *FanoutWriterTestSuite) 
TestBinaryPartitionValuesDoNotAliasArrowStorage(
                icebergType iceberg.Type
        }{
                {name: "binary", arrowType: arrow.BinaryTypes.Binary, 
icebergType: iceberg.PrimitiveTypes.Binary},
-               {name: "fixed", arrowType: 
&arrow.FixedSizeBinaryType{ByteWidth: 4}, icebergType: iceberg.FixedTypeOf(4)},
+               {name: "fixed", arrowType: 
&arrow.FixedSizeBinaryType{ByteWidth: 4}, icebergType: 
iceberg.MustFixedTypeOf(4)},
        }
 
        for _, test := range tests {
@@ -170,7 +170,7 @@ func (s *FanoutWriterTestSuite) 
TestFixedSizeBinaryPartitionReportsWidthMismatch
        defer record.Release()
 
        icebergSchema := iceberg.NewSchema(1, iceberg.NestedField{
-               ID: 1, Name: "part", Type: iceberg.FixedTypeOf(3),
+               ID: 1, Name: "part", Type: iceberg.MustFixedTypeOf(3),
        })
        spec := iceberg.NewPartitionSpec(iceberg.PartitionField{
                SourceIDs: []int{1}, FieldID: 1000, Name: "part", Transform: 
iceberg.IdentityTransform{},
diff --git a/table/partitioned_fanout_writer_test.go 
b/table/partitioned_fanout_writer_test.go
index 3ed322643..e70bc008a 100644
--- a/table/partitioned_fanout_writer_test.go
+++ b/table/partitioned_fanout_writer_test.go
@@ -315,7 +315,7 @@ func (s *FanoutWriterTestSuite) 
TestBinaryPartitionValuesUseComparableKeys() {
                icebergType iceberg.Type
        }{
                {name: "binary", arrowType: arrow.BinaryTypes.Binary, 
icebergType: iceberg.PrimitiveTypes.Binary},
-               {name: "fixed", arrowType: 
&arrow.FixedSizeBinaryType{ByteWidth: 4}, icebergType: iceberg.FixedTypeOf(4)},
+               {name: "fixed", arrowType: 
&arrow.FixedSizeBinaryType{ByteWidth: 4}, icebergType: 
iceberg.MustFixedTypeOf(4)},
        }
 
        for _, test := range tests {
@@ -2038,13 +2038,13 @@ func (s *FanoutWriterTestSuite) 
TestBoundPartitionTransformsMatchArrowValues() {
                },
                {
                        name:       "bucket decimal",
-                       sourceType: iceberg.DecimalTypeOf(10, 2),
+                       sourceType: iceberg.MustDecimalTypeOf(10, 2),
                        transform:  iceberg.BucketTransform{NumBuckets: 16},
                        build:      buildDecimal,
                },
                {
                        name:       "truncate decimal",
-                       sourceType: iceberg.DecimalTypeOf(10, 2),
+                       sourceType: iceberg.MustDecimalTypeOf(10, 2),
                        transform:  iceberg.TruncateTransform{Width: 10},
                        build:      buildDecimal,
                },
@@ -2064,7 +2064,7 @@ func (s *FanoutWriterTestSuite) 
TestBoundPartitionTransformsMatchArrowValues() {
                },
                {
                        name:       "bucket fixed",
-                       sourceType: iceberg.FixedTypeOf(4),
+                       sourceType: iceberg.MustFixedTypeOf(4),
                        transform:  iceberg.BucketTransform{NumBuckets: 16},
                        build: func() arrow.Array {
                                builder := 
array.NewFixedSizeBinaryBuilder(s.mem, &arrow.FixedSizeBinaryType{ByteWidth: 4})
@@ -2126,7 +2126,7 @@ func (s *FanoutWriterTestSuite) 
TestArrowDecimalValuesPreserveSign() {
        }{
                {
                        name:       "decimal32",
-                       sourceType: iceberg.DecimalTypeOf(8, 2),
+                       sourceType: iceberg.MustDecimalTypeOf(8, 2),
                        build: func() arrow.Array {
                                builder := array.NewDecimal32Builder(s.mem, 
&arrow.Decimal32Type{Precision: 8, Scale: 2})
                                builder.Append(arrowdecimal.Decimal32(-1234))
@@ -2139,7 +2139,7 @@ func (s *FanoutWriterTestSuite) 
TestArrowDecimalValuesPreserveSign() {
                },
                {
                        name:       "decimal64",
-                       sourceType: iceberg.DecimalTypeOf(18, 2),
+                       sourceType: iceberg.MustDecimalTypeOf(18, 2),
                        build: func() arrow.Array {
                                builder := array.NewDecimal64Builder(s.mem, 
&arrow.Decimal64Type{Precision: 18, Scale: 2})
                                builder.Append(arrowdecimal.Decimal64(-1234))
@@ -2236,7 +2236,7 @@ func (s *FanoutWriterTestSuite) TestVoidTransform() {
 func (s *FanoutWriterTestSuite) 
TestPartitionedLogicalTypesRequireIntFieldIDCase() {
        icebergSchema := iceberg.NewSchemaWithIdentifiers(1, []int{1},
                iceberg.NestedField{ID: 1, Name: "id", Type: 
iceberg.PrimitiveTypes.Int64, Required: true},
-               iceberg.NestedField{ID: 2, Name: "decimal_col", Type: 
iceberg.DecimalTypeOf(10, 6), Required: true},
+               iceberg.NestedField{ID: 2, Name: "decimal_col", Type: 
iceberg.MustDecimalTypeOf(10, 6), Required: true},
                iceberg.NestedField{ID: 3, Name: "time_col", Type: 
iceberg.PrimitiveTypes.Time, Required: true},
                iceberg.NestedField{ID: 4, Name: "timestamp_col", Type: 
iceberg.PrimitiveTypes.Timestamp, Required: true},
                iceberg.NestedField{ID: 5, Name: "timestamptz_col", Type: 
iceberg.PrimitiveTypes.TimestampTz, Required: true},
diff --git a/table/scanner_internal_test.go b/table/scanner_internal_test.go
index 59467f3ed..441ac4888 100644
--- a/table/scanner_internal_test.go
+++ b/table/scanner_internal_test.go
@@ -2368,7 +2368,7 @@ func TestArrowScanFiltersMissingColumnInitialDefault(t 
*testing.T) {
                ).
                AddColumn(
                        []string{"new_decimal"},
-                       iceberg.DecimalTypeOf(9, 2),
+                       iceberg.MustDecimalTypeOf(9, 2),
                        "",
                        false,
                        iceberg.DecimalLiteral(decimalDefault),
diff --git a/table/substrait/substrait_decimal_internal_test.go 
b/table/substrait/substrait_decimal_internal_test.go
index 50f70d961..ab7c2ce96 100644
--- a/table/substrait/substrait_decimal_internal_test.go
+++ b/table/substrait/substrait_decimal_internal_test.go
@@ -58,7 +58,7 @@ func TestToDecimalLiteralUsesBoundFieldPrecision(t 
*testing.T) {
 
        for _, tc := range cases {
                t.Run(tc.name, func(t *testing.T) {
-                       fieldType := iceberg.DecimalTypeOf(tc.precision, 
tc.scale)
+                       fieldType := iceberg.MustDecimalTypeOf(tc.precision, 
tc.scale)
                        lit := decimalLiteral16Bytes(tc.scale)
 
                        got := toDecimalLiteral(fieldType, lit)
@@ -118,7 +118,7 @@ func TestToDecimalLiteralRealisticValues(t *testing.T) {
 
        for _, tc := range cases {
                t.Run(tc.name, func(t *testing.T) {
-                       fieldType := iceberg.DecimalTypeOf(18, tc.scale)
+                       fieldType := iceberg.MustDecimalTypeOf(18, tc.scale)
                        lit := iceberg.DecimalLiteral{Val: tc.val, Scale: 
tc.scale}
 
                        got := toDecimalLiteral(fieldType, lit)
diff --git a/table/substrait/substrait_test.go 
b/table/substrait/substrait_test.go
index fffc39470..9d4f380ce 100644
--- a/table/substrait/substrait_test.go
+++ b/table/substrait/substrait_test.go
@@ -38,11 +38,11 @@ func TestRefTypes(t *testing.T) {
                iceberg.NestedField{ID: 6, Name: "f", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 7, Name: "g", Type: 
iceberg.PrimitiveTypes.Time},
                iceberg.NestedField{ID: 8, Name: "h", Type: 
iceberg.PrimitiveTypes.Timestamp},
-               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.DecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
                iceberg.NestedField{ID: 10, Name: "j", Type: 
iceberg.PrimitiveTypes.String},
                iceberg.NestedField{ID: 11, Name: "k", Type: 
iceberg.PrimitiveTypes.Binary},
                iceberg.NestedField{ID: 12, Name: "l", Type: 
iceberg.PrimitiveTypes.UUID},
-               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.FixedTypeOf(5)})
+               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.MustFixedTypeOf(5)})
 
        tests := []struct {
                name string
diff --git a/table/table_test.go b/table/table_test.go
index dae8b35fd..35d370910 100644
--- a/table/table_test.go
+++ b/table/table_test.go
@@ -2537,10 +2537,10 @@ func tableSchema() *iceberg.Schema {
                iceberg.NestedField{ID: 11, Name: "date", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 12, Name: "uuid", Type: 
iceberg.PrimitiveTypes.UUID},
                iceberg.NestedField{ID: 13, Name: "binary", Type: 
iceberg.PrimitiveTypes.Binary},
-               iceberg.NestedField{ID: 14, Name: "fixed", Type: 
iceberg.FixedTypeOf(16)},
-               iceberg.NestedField{ID: 15, Name: "small_dec", Type: 
iceberg.DecimalTypeOf(8, 2)},
-               iceberg.NestedField{ID: 16, Name: "med_dec", Type: 
iceberg.DecimalTypeOf(16, 2)},
-               iceberg.NestedField{ID: 17, Name: "large_dec", Type: 
iceberg.DecimalTypeOf(24, 2)},
+               iceberg.NestedField{ID: 14, Name: "fixed", Type: 
iceberg.MustFixedTypeOf(16)},
+               iceberg.NestedField{ID: 15, Name: "small_dec", Type: 
iceberg.MustDecimalTypeOf(8, 2)},
+               iceberg.NestedField{ID: 16, Name: "med_dec", Type: 
iceberg.MustDecimalTypeOf(16, 2)},
+               iceberg.NestedField{ID: 17, Name: "large_dec", Type: 
iceberg.MustDecimalTypeOf(24, 2)},
        )
 }
 
diff --git a/table/transaction_test.go b/table/transaction_test.go
index cf323caa1..e035171a5 100644
--- a/table/transaction_test.go
+++ b/table/transaction_test.go
@@ -191,10 +191,10 @@ func (s *SparkIntegrationTestSuite) 
TestDifferentDataTypes() {
                iceberg.NestedField{ID: 10, Name: "date", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 11, Name: "uuid", Type: 
iceberg.PrimitiveTypes.UUID},
                iceberg.NestedField{ID: 12, Name: "binary", Type: 
iceberg.PrimitiveTypes.Binary},
-               iceberg.NestedField{ID: 13, Name: "fixed", Type: 
iceberg.FixedTypeOf(16)},
-               iceberg.NestedField{ID: 14, Name: "small_dec", Type: 
iceberg.DecimalTypeOf(8, 2)},
-               iceberg.NestedField{ID: 15, Name: "med_dec", Type: 
iceberg.DecimalTypeOf(16, 2)},
-               iceberg.NestedField{ID: 16, Name: "large_dec", Type: 
iceberg.DecimalTypeOf(24, 2)},
+               iceberg.NestedField{ID: 13, Name: "fixed", Type: 
iceberg.MustFixedTypeOf(16)},
+               iceberg.NestedField{ID: 14, Name: "small_dec", Type: 
iceberg.MustDecimalTypeOf(8, 2)},
+               iceberg.NestedField{ID: 15, Name: "med_dec", Type: 
iceberg.MustDecimalTypeOf(16, 2)},
+               iceberg.NestedField{ID: 16, Name: "large_dec", Type: 
iceberg.MustDecimalTypeOf(24, 2)},
                iceberg.NestedField{
                        ID: 17, Name: "list", Type: &iceberg.ListType{
                                ElementID: 18,
diff --git a/table/update_schema_test.go b/table/update_schema_test.go
index 3d46f97ea..6ad7ca53b 100644
--- a/table/update_schema_test.go
+++ b/table/update_schema_test.go
@@ -1833,10 +1833,10 @@ func TestUnionByNamePromoteFloatToDouble(t *testing.T) {
 
 func TestUnionByNamePromoteDecimalPrecision(t *testing.T) {
        current := iceberg.NewSchema(1,
-               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.DecimalTypeOf(9, 2), Required: true},
+               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(9, 2), Required: true},
        )
        incoming := iceberg.NewSchema(1,
-               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.DecimalTypeOf(18, 2), Required: true},
+               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(18, 2), Required: true},
        )
 
        applied, err := NewUpdateSchema(unionTxn(t, current), true, 
false).UnionByNameWith(incoming).Apply()
@@ -1844,7 +1844,7 @@ func TestUnionByNamePromoteDecimalPrecision(t *testing.T) 
{
 
        amount, ok := applied.FindFieldByName("amount")
        require.True(t, ok)
-       assert.Equal(t, iceberg.DecimalTypeOf(18, 2), amount.Type)
+       assert.Equal(t, iceberg.MustDecimalTypeOf(18, 2), amount.Type)
 }
 
 func TestUnionByNameIgnoreNarrowingType(t *testing.T) {
@@ -2334,11 +2334,11 @@ func TestUnionByNameRejectsMistypedNativeDefault(t 
*testing.T) {
 
 func TestUnionByNamePromoteDecimalKeepsWiderWriteDefault(t *testing.T) {
        current := iceberg.NewSchema(1,
-               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.DecimalTypeOf(9, 2), Required: true},
+               iceberg.NestedField{ID: 1, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(9, 2), Required: true},
        )
        incoming := iceberg.NewSchema(1,
                iceberg.NestedField{
-                       ID: 1, Name: "amount", Type: iceberg.DecimalTypeOf(18, 
2), Required: true,
+                       ID: 1, Name: "amount", Type: 
iceberg.MustDecimalTypeOf(18, 2), Required: true,
                        WriteDefault: "123456789.12",
                },
        )
@@ -2348,7 +2348,7 @@ func 
TestUnionByNamePromoteDecimalKeepsWiderWriteDefault(t *testing.T) {
 
        amount, ok := applied.FindFieldByName("amount")
        require.True(t, ok)
-       assert.Equal(t, iceberg.DecimalTypeOf(18, 2), amount.Type)
+       assert.Equal(t, iceberg.MustDecimalTypeOf(18, 2), amount.Type)
        assert.Equal(t, "123456789.12", amount.WriteDefault)
 }
 
@@ -2553,8 +2553,8 @@ func TestUnionByNameRejectsInvalidPromotions(t 
*testing.T) {
        }{
                {"string -> binary", iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary},
                {"binary -> string", iceberg.PrimitiveTypes.Binary, 
iceberg.PrimitiveTypes.String},
-               {"fixed[16] -> uuid", iceberg.FixedTypeOf(16), 
iceberg.PrimitiveTypes.UUID},
-               {"decimal scale widening", iceberg.DecimalTypeOf(10, 1), 
iceberg.DecimalTypeOf(10, 2)},
+               {"fixed[16] -> uuid", iceberg.MustFixedTypeOf(16), 
iceberg.PrimitiveTypes.UUID},
+               {"decimal scale widening", iceberg.MustDecimalTypeOf(10, 1), 
iceberg.MustDecimalTypeOf(10, 2)},
                {"string -> int", iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Int32},
        }
 
diff --git a/table/variant_residual_fastpath_test.go 
b/table/variant_residual_fastpath_test.go
index 2ac4c3b49..74b7f265a 100644
--- a/table/variant_residual_fastpath_test.go
+++ b/table/variant_residual_fastpath_test.go
@@ -375,10 +375,10 @@ func TestFastPathDecimalScaleNearMissFallsBack(t 
*testing.T) {
        defer rec.Release()
 
        iceSchema := iceberg.NewSchema(0, iceberg.NestedField{ID: 2, Name: 
"payload", Type: iceberg.VariantType{}})
-       term, err := iceberg.Extract("payload", "$.a", 
iceberg.DecimalTypeOf(10, 4)).Bind(iceSchema, true)
+       term, err := iceberg.Extract("payload", "$.a", 
iceberg.MustDecimalTypeOf(10, 4)).Bind(iceSchema, true)
        require.NoError(t, err)
        col := iceberg.VariantExtractColumn{Term: term.(iceberg.BoundExtract), 
FieldID: 100, Name: "_x", SourcePath: []string{"payload"}}
-       dt, err := TypeToArrowType(iceberg.DecimalTypeOf(10, 4), false, false)
+       dt, err := TypeToArrowType(iceberg.MustDecimalTypeOf(10, 4), false, 
false)
        require.NoError(t, err)
 
        require.Nil(t, tryShreddedTypedColumn(varr, vpath(t, col.Term), dt, 
mem), "scale near-miss must not fast-path")
diff --git a/table/variant_residual_test.go b/table/variant_residual_test.go
index 4ae5eea7f..72524bd10 100644
--- a/table/variant_residual_test.go
+++ b/table/variant_residual_test.go
@@ -49,12 +49,12 @@ func TestAppendExtractLiteral(t *testing.T) {
                {"string", iceberg.PrimitiveTypes.String, 
iceberg.NewLiteral("hi"), "hi"},
                {"binary", iceberg.PrimitiveTypes.Binary, 
iceberg.NewLiteral([]byte{1, 2}), []byte{1, 2}},
                {"uuid", iceberg.PrimitiveTypes.UUID, 
iceberg.NewLiteral(uuid.UUID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 
16}), uuid.UUID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}},
-               {"fixed", iceberg.FixedTypeOf(16), 
iceberg.NewLiteral(make([]byte, 16)), make([]byte, 16)},
+               {"fixed", iceberg.MustFixedTypeOf(16), 
iceberg.NewLiteral(make([]byte, 16)), make([]byte, 16)},
                {"date", iceberg.PrimitiveTypes.Date, 
iceberg.NewLiteral(iceberg.Date(100)), arrow.Date32(100)},
                {"time", iceberg.PrimitiveTypes.Time, 
iceberg.NewLiteral(iceberg.Time(1_000_000)), arrow.Time64(1_000_000)},
                {"timestamp micros", iceberg.PrimitiveTypes.Timestamp, 
iceberg.NewLiteral(iceberg.Timestamp(123)), arrow.Timestamp(123)},
                {"timestamp nanos", iceberg.PrimitiveTypes.TimestampNs, 
iceberg.NewLiteral(iceberg.TimestampNano(123)), arrow.Timestamp(123)},
-               {"decimal", iceberg.DecimalTypeOf(10, 2), 
iceberg.NewLiteral(iceberg.Decimal{Val: decimal128.FromI64(1234), Scale: 2}), 
decimal128.FromI64(1234)},
+               {"decimal", iceberg.MustDecimalTypeOf(10, 2), 
iceberg.NewLiteral(iceberg.Decimal{Val: decimal128.FromI64(1234), Scale: 2}), 
decimal128.FromI64(1234)},
        } {
                t.Run(tt.name, func(t *testing.T) {
                        dt, err := TypeToArrowType(tt.typ, false, false)
diff --git a/table/variant_shredded_write_test.go 
b/table/variant_shredded_write_test.go
index d7157c527..4586f52f6 100644
--- a/table/variant_shredded_write_test.go
+++ b/table/variant_shredded_write_test.go
@@ -806,7 +806,7 @@ func TestShreddedVariantWriteRegularDecimalStats(t 
*testing.T) {
        mem := memory.DefaultAllocator
        iceSchema := iceberg.NewSchema(0,
                iceberg.NestedField{ID: 1, Name: "id", Type: 
iceberg.PrimitiveTypes.Int64, Required: true},
-               iceberg.NestedField{ID: 2, Name: "price", Type: 
iceberg.DecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 2, Name: "price", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
                iceberg.NestedField{ID: 3, Name: "payload", Type: 
iceberg.VariantType{}},
        )
        arrSchema, err := SchemaToArrowSchema(iceSchema, nil, true, false)
@@ -861,7 +861,7 @@ func TestShreddedVariantWriteRegularDecimalStats(t 
*testing.T) {
        // off and the regular decimal column keeps its default 
FIXED_LEN_BYTE_ARRAY.
        assert.Equal(t, parquet.Types.FixedLenByteArray, columnPhysicalType(t, 
files[0].FilePath(), "price"))
 
-       decTyp := iceberg.DecimalTypeOf(9, 2)
+       decTyp := iceberg.MustDecimalTypeOf(9, 2)
        lb, err := iceberg.LiteralFromBytes(decTyp, 
files[0].LowerBoundValues()[2])
        require.NoError(t, err)
        ub, err := iceberg.LiteralFromBytes(decTyp, 
files[0].UpperBoundValues()[2])
@@ -878,7 +878,7 @@ func 
TestShreddedVariantWriteRegularDecimalWithShreddedDecimal(t *testing.T) {
        mem := memory.DefaultAllocator
        iceSchema := iceberg.NewSchema(0,
                iceberg.NestedField{ID: 1, Name: "id", Type: 
iceberg.PrimitiveTypes.Int64, Required: true},
-               iceberg.NestedField{ID: 2, Name: "price", Type: 
iceberg.DecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 2, Name: "price", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
                iceberg.NestedField{ID: 3, Name: "payload", Type: 
iceberg.VariantType{}},
        )
        arrSchema, err := SchemaToArrowSchema(iceSchema, nil, true, false)
@@ -936,7 +936,7 @@ func 
TestShreddedVariantWriteRegularDecimalWithShreddedDecimal(t *testing.T) {
 
        // Bounds are derived from the Arrow values, so they must be correct 
regardless of
        // the INT physical encoding.
-       decTyp := iceberg.DecimalTypeOf(9, 2)
+       decTyp := iceberg.MustDecimalTypeOf(9, 2)
        lb, err := iceberg.LiteralFromBytes(decTyp, 
files[0].LowerBoundValues()[2])
        require.NoError(t, err)
        ub, err := iceberg.LiteralFromBytes(decTyp, 
files[0].UpperBoundValues()[2])
diff --git a/transforms_decimal_bench_test.go b/transforms_decimal_bench_test.go
index 67c61b4f7..b41c3e36b 100644
--- a/transforms_decimal_bench_test.go
+++ b/transforms_decimal_bench_test.go
@@ -62,7 +62,7 @@ func BenchmarkBucketTransformDecimal(b *testing.B) {
        })
 
        b.Run("Transformer", func(b *testing.B) {
-               transformer := transform.Transformer(iceberg.DecimalTypeOf(38, 
0))
+               transformer := 
transform.Transformer(iceberg.MustDecimalTypeOf(38, 0))
                b.ReportAllocs()
                b.ResetTimer()
                for i := range b.N {
@@ -112,7 +112,7 @@ func BenchmarkTruncateTransformDecimal(b *testing.B) {
                        }
                })
                b.Run(tt.name+"/Transformer", func(b *testing.B) {
-                       transformer, err := 
transform.Transformer(iceberg.DecimalTypeOf(38, 2))
+                       transformer, err := 
transform.Transformer(iceberg.MustDecimalTypeOf(38, 2))
                        if err != nil {
                                b.Fatal(err)
                        }
diff --git a/transforms_test.go b/transforms_test.go
index 15c449131..2f27195ff 100644
--- a/transforms_test.go
+++ b/transforms_test.go
@@ -244,7 +244,7 @@ func TestToHumanStringValues(t *testing.T) {
                {iceberg.VoidTransform{}, iceberg.PrimitiveTypes.String, nil, 
"null"},
                {iceberg.IdentityTransform{}, iceberg.PrimitiveTypes.String, 
nil, "null"},
                {iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.Binary, []byte{0x00, 0x01, 0x02, 0x03}, "AAECAw=="},
-               {iceberg.TruncateTransform{Width: 1}, iceberg.DecimalTypeOf(9, 
2), iceberg.Decimal{
+               {iceberg.TruncateTransform{Width: 1}, 
iceberg.MustDecimalTypeOf(9, 2), iceberg.Decimal{
                        Val: decVal, Scale: 2,
                }, "14.21"},
                {iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.Int32, int32(123), "123"},
@@ -258,7 +258,7 @@ func TestToHumanStringValues(t *testing.T) {
                {iceberg.IdentityTransform{}, iceberg.PrimitiveTypes.Int64, 
int64(-1234567890000), "-1234567890000"},
                {iceberg.IdentityTransform{}, iceberg.PrimitiveTypes.String, 
"a/b/c=d", "a/b/c=d"},
                {iceberg.IdentityTransform{}, iceberg.PrimitiveTypes.Binary, 
[]byte("foo"), "Zm9v"},
-               {iceberg.IdentityTransform{}, iceberg.DecimalTypeOf(9, 2), 
iceberg.Decimal{Val: negDecVal, Scale: 2}, "-1.50"},
+               {iceberg.IdentityTransform{}, iceberg.MustDecimalTypeOf(9, 2), 
iceberg.Decimal{Val: negDecVal, Scale: 2}, "-1.50"},
        }
 
        for _, tt := range tests {
@@ -297,7 +297,7 @@ func TestToHumanString(t *testing.T) {
                {"truncate_int32", iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.Int32, int32(123), "123"},
                {"truncate_string", iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.String, "foo", "foo"},
                {"truncate_bytes", iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.Binary, []byte{0x00, 0x01, 0x02, 0x03}, "AAECAw=="},
-               {"truncate_decimal", iceberg.TruncateTransform{Width: 1}, 
iceberg.DecimalTypeOf(4, 2), iceberg.Decimal{Val: decVal, Scale: 2}, "14.21"},
+               {"truncate_decimal", iceberg.TruncateTransform{Width: 1}, 
iceberg.MustDecimalTypeOf(4, 2), iceberg.Decimal{Val: decVal, Scale: 2}, 
"14.21"},
                {"truncate_nil", iceberg.TruncateTransform{Width: 1}, 
iceberg.PrimitiveTypes.String, nil, "null"},
                {"void", iceberg.VoidTransform{}, 
iceberg.PrimitiveTypes.TimestampTz, tsMicros, "null"},
                {"void_nil", iceberg.VoidTransform{}, 
iceberg.PrimitiveTypes.String, nil, "null"},
@@ -597,7 +597,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Date,
                                iceberg.PrimitiveTypes.Time, 
iceberg.PrimitiveTypes.Timestamp, iceberg.PrimitiveTypes.TimestampTz,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.FixedTypeOf(2),
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.MustFixedTypeOf(2),
                        },
                        notAllowed: []iceberg.Type{
                                &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
@@ -614,7 +614,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Time, 
iceberg.PrimitiveTypes.Timestamp, iceberg.PrimitiveTypes.TimestampTz,
                                iceberg.PrimitiveTypes.TimestampNs, 
iceberg.PrimitiveTypes.TimestampTzNs,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.FixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.MustFixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
                                iceberg.GeographyType{},
                                iceberg.GeometryType{},
@@ -627,7 +627,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Int32, 
iceberg.PrimitiveTypes.Int64, iceberg.PrimitiveTypes.Date,
                                iceberg.PrimitiveTypes.Time, 
iceberg.PrimitiveTypes.Timestamp, iceberg.PrimitiveTypes.TimestampTz,
                                iceberg.PrimitiveTypes.TimestampNs, 
iceberg.PrimitiveTypes.TimestampTzNs,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.PrimitiveTypes.String, iceberg.FixedTypeOf(2), 
iceberg.PrimitiveTypes.Binary,
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.PrimitiveTypes.String, iceberg.MustFixedTypeOf(2), 
iceberg.PrimitiveTypes.Binary,
                                iceberg.PrimitiveTypes.UUID,
                        },
                        notAllowed: []iceberg.Type{
@@ -642,12 +642,12 @@ func TestCanTransform(t *testing.T) {
                        transform: iceberg.TruncateTransform{},
                        allowed: []iceberg.Type{
                                iceberg.PrimitiveTypes.Int32, 
iceberg.PrimitiveTypes.Int64, iceberg.PrimitiveTypes.String,
-                               iceberg.PrimitiveTypes.Binary, 
iceberg.DecimalTypeOf(2, 1),
+                               iceberg.PrimitiveTypes.Binary, 
iceberg.MustDecimalTypeOf(2, 1),
                        },
                        notAllowed: []iceberg.Type{
                                iceberg.PrimitiveTypes.Bool, 
iceberg.PrimitiveTypes.Float32, iceberg.PrimitiveTypes.Float64,
                                iceberg.PrimitiveTypes.Date, 
iceberg.PrimitiveTypes.Time, iceberg.PrimitiveTypes.Timestamp,
-                               iceberg.PrimitiveTypes.TimestampTz, 
iceberg.PrimitiveTypes.UUID, iceberg.FixedTypeOf(2),
+                               iceberg.PrimitiveTypes.TimestampTz, 
iceberg.PrimitiveTypes.UUID, iceberg.MustFixedTypeOf(2),
                                iceberg.PrimitiveTypes.TimestampNs, 
iceberg.PrimitiveTypes.TimestampTzNs,
                                &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
@@ -665,7 +665,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Bool, 
iceberg.PrimitiveTypes.Int32, iceberg.PrimitiveTypes.Int64,
                                iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Time,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.FixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.MustFixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
                                iceberg.GeographyType{},
                                iceberg.GeometryType{},
@@ -681,7 +681,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Bool, 
iceberg.PrimitiveTypes.Int32, iceberg.PrimitiveTypes.Int64,
                                iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Time,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.FixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.MustFixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
                                iceberg.GeographyType{},
                                iceberg.GeometryType{},
@@ -697,7 +697,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Bool, 
iceberg.PrimitiveTypes.Int32, iceberg.PrimitiveTypes.Int64,
                                iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Time,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.DecimalTypeOf(2, 1), 
iceberg.FixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
+                               iceberg.MustDecimalTypeOf(2, 1), 
iceberg.MustFixedTypeOf(2), &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
                                iceberg.GeographyType{},
                                iceberg.GeometryType{},
@@ -713,7 +713,7 @@ func TestCanTransform(t *testing.T) {
                                iceberg.PrimitiveTypes.Bool, 
iceberg.PrimitiveTypes.Int32, iceberg.PrimitiveTypes.Int64,
                                iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Time,
                                iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.UUID,
-                               iceberg.PrimitiveTypes.Date, 
iceberg.DecimalTypeOf(2, 1), iceberg.FixedTypeOf(2),
+                               iceberg.PrimitiveTypes.Date, 
iceberg.MustDecimalTypeOf(2, 1), iceberg.MustFixedTypeOf(2),
                                &iceberg.StructType{}, &iceberg.ListType{}, 
&iceberg.MapType{},
                                iceberg.VariantType{},
                                iceberg.GeographyType{},
@@ -1198,7 +1198,7 @@ func TestTruncateTransformDecimal(t *testing.T) {
        for _, width := range []int{1, 2, 3, 10, 50, 97, math.MaxInt32} {
                transform := iceberg.TruncateTransform{Width: width}
                for _, scale := range []int{0, 2, 9, 38} {
-                       transformer, err := 
transform.Transformer(iceberg.DecimalTypeOf(38, scale))
+                       transformer, err := 
transform.Transformer(iceberg.MustDecimalTypeOf(38, scale))
                        require.NoError(t, err)
                        for _, value := range values {
                                t.Run(fmt.Sprintf("width=%d/scale=%d/value=%s", 
width, scale, value), func(t *testing.T) {
@@ -1229,7 +1229,7 @@ func TestTruncateTransformDecimal(t *testing.T) {
 
        t.Run("null", func(t *testing.T) {
                transform := iceberg.TruncateTransform{Width: 50}
-               transformer, err := 
transform.Transformer(iceberg.DecimalTypeOf(38, 2))
+               transformer, err := 
transform.Transformer(iceberg.MustDecimalTypeOf(38, 2))
                require.NoError(t, err)
                assert.Nil(t, transformer(nil))
                assert.False(t, 
transform.Apply(iceberg.Optional[iceberg.Literal]{Valid: false}).Valid)
diff --git a/types.go b/types.go
index 7407c1dba..adabde404 100644
--- a/types.go
+++ b/types.go
@@ -644,12 +644,24 @@ func validateFixedLength(length int) error {
        return nil
 }
 
-func FixedTypeOf(n int) FixedType {
+// FixedTypeOf returns the fixed type with the specified length.
+// It returns ErrInvalidArgument if the length is negative.
+func FixedTypeOf(n int) (FixedType, error) {
        if err := validateFixedLength(n); err != nil {
-               panic(fmt.Errorf("%w: %s", ErrInvalidArgument, err))
+               return FixedType{}, fmt.Errorf("%w: %w", ErrInvalidArgument, 
err)
        }
 
-       return FixedType{len: n}
+       return FixedType{len: n}, nil
+}
+
+// MustFixedTypeOf is like FixedTypeOf but panics if the length is negative.
+func MustFixedTypeOf(n int) FixedType {
+       typ, err := FixedTypeOf(n)
+       if err != nil {
+               panic(err)
+       }
+
+       return typ
 }
 
 type FixedType struct {
@@ -669,12 +681,24 @@ func (f FixedType) Type() string   { return 
fmt.Sprintf("fixed[%d]", f.len) }
 func (f FixedType) String() string { return fmt.Sprintf("fixed[%d]", f.len) }
 func (f FixedType) primitive()     {}
 
-func DecimalTypeOf(prec, scale int) DecimalType {
+// DecimalTypeOf returns the decimal type with the specified precision and 
scale.
+// It returns ErrInvalidArgument if either value is outside the valid range.
+func DecimalTypeOf(prec, scale int) (DecimalType, error) {
        if err := validateDecimalPrecisionScale(prec, scale); err != nil {
-               panic(fmt.Errorf("%w: %w", ErrInvalidArgument, err))
+               return DecimalType{}, fmt.Errorf("%w: %w", ErrInvalidArgument, 
err)
+       }
+
+       return DecimalType{precision: prec, scale: scale}, nil
+}
+
+// MustDecimalTypeOf is like DecimalTypeOf but panics for an invalid precision 
or scale.
+func MustDecimalTypeOf(prec, scale int) DecimalType {
+       typ, err := DecimalTypeOf(prec, scale)
+       if err != nil {
+               panic(err)
        }
 
-       return DecimalType{precision: prec, scale: scale}
+       return typ
 }
 
 func validateDecimalPrecisionScale(precision, scale int) error {
diff --git a/types_test.go b/types_test.go
index eb752cfb2..eb3a453cd 100644
--- a/types_test.go
+++ b/types_test.go
@@ -47,10 +47,10 @@ func TestTypesBasic(t *testing.T) {
                {"binary", iceberg.PrimitiveTypes.Binary},
                {"unknown", iceberg.PrimitiveTypes.Unknown},
                {"variant", iceberg.VariantType{}},
-               {"fixed[0]", iceberg.FixedTypeOf(0)},
-               {"fixed[5]", iceberg.FixedTypeOf(5)},
-               {"decimal(9, 4)", iceberg.DecimalTypeOf(9, 4)},
-               {"decimal(5, 5)", iceberg.DecimalTypeOf(5, 5)},
+               {"fixed[0]", iceberg.MustFixedTypeOf(0)},
+               {"fixed[5]", iceberg.MustFixedTypeOf(5)},
+               {"decimal(9, 4)", iceberg.MustDecimalTypeOf(9, 4)},
+               {"decimal(5, 5)", iceberg.MustDecimalTypeOf(5, 5)},
        }
 
        for _, tt := range tests {
@@ -74,12 +74,12 @@ func TestTypesBasic(t *testing.T) {
 }
 
 func TestFixedType(t *testing.T) {
-       typ := iceberg.FixedTypeOf(5)
+       typ := iceberg.MustFixedTypeOf(5)
        assert.Equal(t, 5, typ.Len())
        assert.Equal(t, "fixed[5]", typ.String())
-       assert.True(t, typ.Equals(iceberg.FixedTypeOf(5)))
-       assert.False(t, typ.Equals(iceberg.FixedTypeOf(6)))
-       assert.Equal(t, "fixed[0]", iceberg.FixedTypeOf(0).String())
+       assert.True(t, typ.Equals(iceberg.MustFixedTypeOf(5)))
+       assert.False(t, typ.Equals(iceberg.MustFixedTypeOf(6)))
+       assert.Equal(t, "fixed[0]", iceberg.MustFixedTypeOf(0).String())
 
        t.Run("FixedTypeOf validates length", func(t *testing.T) {
                assertFixedTypeOfPanicsWithInvalidArgument(t, -1)
@@ -129,30 +129,30 @@ func assertFixedTypeOfPanicsWithInvalidArgument(t 
*testing.T, length int) {
                assert.ErrorIs(t, err, iceberg.ErrInvalidArgument)
        }()
 
-       iceberg.FixedTypeOf(length)
+       iceberg.MustFixedTypeOf(length)
 }
 
 func TestDecimalType(t *testing.T) {
-       typ := iceberg.DecimalTypeOf(9, 2)
+       typ := iceberg.MustDecimalTypeOf(9, 2)
        assert.Equal(t, 9, typ.Precision())
        assert.Equal(t, 2, typ.Scale())
        assert.Equal(t, "decimal(9, 2)", typ.String())
-       assert.True(t, typ.Equals(iceberg.DecimalTypeOf(9, 2)))
-       assert.False(t, typ.Equals(iceberg.DecimalTypeOf(9, 3)))
+       assert.True(t, typ.Equals(iceberg.MustDecimalTypeOf(9, 2)))
+       assert.False(t, typ.Equals(iceberg.MustDecimalTypeOf(9, 3)))
 
        t.Run("DecimalTypeOf validates precision and scale", func(t *testing.T) 
{
                assert.PanicsWithError(t, "invalid argument: invalid precision 
0: must be greater than 0", func() {
-                       iceberg.DecimalTypeOf(0, 2)
+                       iceberg.MustDecimalTypeOf(0, 2)
                })
                assert.PanicsWithError(t, "invalid argument: invalid precision 
39: must be less than or equal to 38", func() {
-                       iceberg.DecimalTypeOf(39, 0)
+                       iceberg.MustDecimalTypeOf(39, 0)
                })
-               assert.Equal(t, "decimal(10, 10)", iceberg.DecimalTypeOf(10, 
10).String())
+               assert.Equal(t, "decimal(10, 10)", 
iceberg.MustDecimalTypeOf(10, 10).String())
                assert.PanicsWithError(t, "invalid argument: invalid scale -1: 
must be greater than or equal to 0", func() {
-                       iceberg.DecimalTypeOf(10, -1)
+                       iceberg.MustDecimalTypeOf(10, -1)
                })
                assert.PanicsWithError(t, "invalid argument: invalid scale 6: 
must be less than or equal to precision 5", func() {
-                       iceberg.DecimalTypeOf(5, 6)
+                       iceberg.MustDecimalTypeOf(5, 6)
                })
        })
 }
@@ -197,10 +197,10 @@ func TestStructType(t *testing.T) {
        typ := &iceberg.StructType{
                FieldList: []iceberg.NestedField{
                        {ID: 1, Name: "required_field", Type: 
iceberg.PrimitiveTypes.Int32, Required: true},
-                       {ID: 2, Name: "optional_field", Type: 
iceberg.FixedTypeOf(5), Required: false},
+                       {ID: 2, Name: "optional_field", Type: 
iceberg.MustFixedTypeOf(5), Required: false},
                        {ID: 3, Name: "required_field", Type: 
&iceberg.StructType{
                                FieldList: []iceberg.NestedField{
-                                       {ID: 4, Name: "optional_field", Type: 
iceberg.DecimalTypeOf(8, 2), Required: false},
+                                       {ID: 4, Name: "optional_field", Type: 
iceberg.MustDecimalTypeOf(8, 2), Required: false},
                                        {ID: 5, Name: "required_field", Type: 
iceberg.PrimitiveTypes.Int64, Required: false},
                                },
                        }, Required: false},
@@ -223,7 +223,7 @@ func TestListType(t *testing.T) {
                ElementRequired: false,
                Element: &iceberg.StructType{
                        FieldList: []iceberg.NestedField{
-                               {ID: 2, Name: "required_field", Type: 
iceberg.DecimalTypeOf(8, 2), Required: true},
+                               {ID: 2, Name: "required_field", Type: 
iceberg.MustDecimalTypeOf(8, 2), Required: true},
                                {ID: 3, Name: "optional_field", Type: 
iceberg.PrimitiveTypes.Int64, Required: false},
                        },
                },
@@ -237,7 +237,7 @@ func TestListType(t *testing.T) {
                ElementRequired: true,
                Element: &iceberg.StructType{
                        FieldList: []iceberg.NestedField{
-                               {ID: 2, Name: "required_field", Type: 
iceberg.DecimalTypeOf(8, 2), Required: true},
+                               {ID: 2, Name: "required_field", Type: 
iceberg.MustDecimalTypeOf(8, 2), Required: true},
                        },
                },
        }))
@@ -356,8 +356,8 @@ func TestTypeStrings(t *testing.T) {
                {iceberg.PrimitiveTypes.Binary, "binary"},
                {iceberg.PrimitiveTypes.Unknown, "unknown"},
                {iceberg.VariantType{}, "variant"},
-               {iceberg.FixedTypeOf(22), "fixed[22]"},
-               {iceberg.DecimalTypeOf(19, 18), "decimal(19, 18)"},
+               {iceberg.MustFixedTypeOf(22), "fixed[22]"},
+               {iceberg.MustDecimalTypeOf(19, 18), "decimal(19, 18)"},
                {&iceberg.StructType{
                        FieldList: []iceberg.NestedField{
                                {ID: 1, Name: "required_field", Type: 
iceberg.PrimitiveTypes.String, Required: true, Doc: "this is a doc"},
@@ -745,7 +745,7 @@ func TestNestedFieldMarshalBinaryDefaultsAsHex(t 
*testing.T) {
                {
                        name: "fixed",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "fixed", Type: 
iceberg.FixedTypeOf(3),
+                               ID: 2, Name: "fixed", Type: 
iceberg.MustFixedTypeOf(3),
                                InitialDefault: iceberg.FixedLiteral{1, 2, 3},
                        },
                        expected: 
`{"id":2,"name":"fixed","required":false,"initial-default":"010203","type":"fixed[3]"}`,
@@ -1123,15 +1123,15 @@ func TestPromoteType(t *testing.T) {
                {"float to double", iceberg.PrimitiveTypes.Float32, 
iceberg.PrimitiveTypes.Float64, iceberg.PrimitiveTypes.Float64, false},
                {"string to binary", iceberg.PrimitiveTypes.String, 
iceberg.PrimitiveTypes.Binary, iceberg.PrimitiveTypes.Binary, false},
                {"binary to string", iceberg.PrimitiveTypes.Binary, 
iceberg.PrimitiveTypes.String, iceberg.PrimitiveTypes.String, false},
-               {"fixed[16] to uuid", iceberg.FixedTypeOf(16), 
iceberg.PrimitiveTypes.UUID, iceberg.PrimitiveTypes.UUID, false},
+               {"fixed[16] to uuid", iceberg.MustFixedTypeOf(16), 
iceberg.PrimitiveTypes.UUID, iceberg.PrimitiveTypes.UUID, false},
                {"unknown to any", iceberg.PrimitiveTypes.Unknown, 
iceberg.PrimitiveTypes.Int64, iceberg.PrimitiveTypes.Int64, false},
 
                // Decimal: precision may widen, scale must stay the same.
-               {"decimal widen precision", iceberg.DecimalTypeOf(9, 2), 
iceberg.DecimalTypeOf(18, 2), iceberg.DecimalTypeOf(18, 2), false},
-               {"decimal same", iceberg.DecimalTypeOf(9, 2), 
iceberg.DecimalTypeOf(9, 2), iceberg.DecimalTypeOf(9, 2), false},
-               {"decimal narrow precision", iceberg.DecimalTypeOf(18, 2), 
iceberg.DecimalTypeOf(9, 2), nil, true},
-               {"decimal increase scale", iceberg.DecimalTypeOf(9, 2), 
iceberg.DecimalTypeOf(18, 4), nil, true},
-               {"decimal decrease scale", iceberg.DecimalTypeOf(9, 4), 
iceberg.DecimalTypeOf(18, 2), nil, true},
+               {"decimal widen precision", iceberg.MustDecimalTypeOf(9, 2), 
iceberg.MustDecimalTypeOf(18, 2), iceberg.MustDecimalTypeOf(18, 2), false},
+               {"decimal same", iceberg.MustDecimalTypeOf(9, 2), 
iceberg.MustDecimalTypeOf(9, 2), iceberg.MustDecimalTypeOf(9, 2), false},
+               {"decimal narrow precision", iceberg.MustDecimalTypeOf(18, 2), 
iceberg.MustDecimalTypeOf(9, 2), nil, true},
+               {"decimal increase scale", iceberg.MustDecimalTypeOf(9, 2), 
iceberg.MustDecimalTypeOf(18, 4), nil, true},
+               {"decimal decrease scale", iceberg.MustDecimalTypeOf(9, 4), 
iceberg.MustDecimalTypeOf(18, 2), nil, true},
 
                // Geo types never promote to or from binary; only identical 
types pass.
                {"geometry same", geom4326, geom4326, geom4326, false},
@@ -1144,7 +1144,7 @@ func TestPromoteType(t *testing.T) {
                {"geography algorithm mismatch", geog, geogKarney, nil, true},
 
                {"disallowed int to string", iceberg.PrimitiveTypes.Int32, 
iceberg.PrimitiveTypes.String, nil, true},
-               {"disallowed fixed[8] to uuid", iceberg.FixedTypeOf(8), 
iceberg.PrimitiveTypes.UUID, nil, true},
+               {"disallowed fixed[8] to uuid", iceberg.MustFixedTypeOf(8), 
iceberg.PrimitiveTypes.UUID, nil, true},
        }
 
        for _, tt := range tests {
@@ -1161,3 +1161,34 @@ func TestPromoteType(t *testing.T) {
                })
        }
 }
+
+func TestFixedTypeOfReturnsError(t *testing.T) {
+       typ, err := iceberg.FixedTypeOf(16)
+       require.NoError(t, err)
+       assert.Equal(t, 16, typ.Len())
+
+       typ, err = iceberg.FixedTypeOf(-1)
+       require.ErrorIs(t, err, iceberg.ErrInvalidArgument)
+       assert.Equal(t, iceberg.FixedType{}, typ)
+}
+
+func TestDecimalTypeOfReturnsError(t *testing.T) {
+       typ, err := iceberg.DecimalTypeOf(10, 2)
+       require.NoError(t, err)
+       assert.Equal(t, 10, typ.Precision())
+       assert.Equal(t, 2, typ.Scale())
+
+       for _, tc := range []struct {
+               precision int
+               scale     int
+       }{
+               {0, 0},
+               {39, 0},
+               {10, -1},
+               {5, 6},
+       } {
+               typ, err := iceberg.DecimalTypeOf(tc.precision, tc.scale)
+               require.ErrorIs(t, err, iceberg.ErrInvalidArgument)
+               assert.Equal(t, iceberg.DecimalType{}, typ)
+       }
+}
diff --git a/variant_cast_test.go b/variant_cast_test.go
index 739822855..285689a39 100644
--- a/variant_cast_test.go
+++ b/variant_cast_test.go
@@ -106,11 +106,11 @@ func TestCastVariantLiteral(t *testing.T) {
                {"date exact", func(b *variant.Builder) error { return 
b.AppendDate(arrow.Date32(100)) }, PrimitiveTypes.Date, Date(100)},
                {"timestamp micros exact", func(b *variant.Builder) error { 
return b.AppendTimestamp(arrow.Timestamp(123), true, false) }, 
PrimitiveTypes.Timestamp, Timestamp(123)},
                {"uuid exact", func(b *variant.Builder) error { return 
b.AppendUUID(testUUID) }, PrimitiveTypes.UUID, testUUID},
-               {"decimal scale match", func(b *variant.Builder) error { return 
b.AppendDecimal8(2, decimal.Decimal64(1234)) }, DecimalTypeOf(10, 2), 
Decimal{Val: decimal128.FromI64(1234), Scale: 2}},
-               {"decimal32 scale match", func(b *variant.Builder) error { 
return b.AppendDecimal4(2, decimal.Decimal32(1234)) }, DecimalTypeOf(10, 2), 
Decimal{Val: decimal128.FromI64(1234), Scale: 2}},
-               {"decimal128 scale match", func(b *variant.Builder) error { 
return b.AppendDecimal16(3, decimal128.FromI64(123456)) }, DecimalTypeOf(20, 
3), Decimal{Val: decimal128.FromI64(123456), Scale: 3}},
-               {"decimal32 scale mismatch", func(b *variant.Builder) error { 
return b.AppendDecimal4(2, decimal.Decimal32(1234)) }, DecimalTypeOf(10, 3), 
nil},
-               {"decimal scale mismatch", func(b *variant.Builder) error { 
return b.AppendDecimal8(2, decimal.Decimal64(1234)) }, DecimalTypeOf(10, 3), 
nil},
+               {"decimal scale match", func(b *variant.Builder) error { return 
b.AppendDecimal8(2, decimal.Decimal64(1234)) }, MustDecimalTypeOf(10, 2), 
Decimal{Val: decimal128.FromI64(1234), Scale: 2}},
+               {"decimal32 scale match", func(b *variant.Builder) error { 
return b.AppendDecimal4(2, decimal.Decimal32(1234)) }, MustDecimalTypeOf(10, 
2), Decimal{Val: decimal128.FromI64(1234), Scale: 2}},
+               {"decimal128 scale match", func(b *variant.Builder) error { 
return b.AppendDecimal16(3, decimal128.FromI64(123456)) }, 
MustDecimalTypeOf(20, 3), Decimal{Val: decimal128.FromI64(123456), Scale: 3}},
+               {"decimal32 scale mismatch", func(b *variant.Builder) error { 
return b.AppendDecimal4(2, decimal.Decimal32(1234)) }, MustDecimalTypeOf(10, 
3), nil},
+               {"decimal scale mismatch", func(b *variant.Builder) error { 
return b.AppendDecimal8(2, decimal.Decimal64(1234)) }, MustDecimalTypeOf(10, 
3), nil},
                {"string not castable to int64", func(b *variant.Builder) error 
{ return b.AppendString("hi") }, PrimitiveTypes.Int64, nil},
                {"nanos floor to micros pre-epoch", func(b *variant.Builder) 
error { return b.AppendTimestamp(arrow.Timestamp(-1500), false, false) }, 
PrimitiveTypes.Timestamp, Timestamp(-2)},
                {"date to nanos overflows int64", func(b *variant.Builder) 
error { return b.AppendDate(arrow.Date32(200_000)) }, 
PrimitiveTypes.TimestampNs, nil},
diff --git a/variant_extract_test.go b/variant_extract_test.go
index 6a137a1c8..5901aaede 100644
--- a/variant_extract_test.go
+++ b/variant_extract_test.go
@@ -175,7 +175,7 @@ func TestExtractBindAllTargetTypes(t *testing.T) {
                PrimitiveTypes.Float32, PrimitiveTypes.Float64, 
PrimitiveTypes.Date,
                PrimitiveTypes.Time, PrimitiveTypes.Timestamp, 
PrimitiveTypes.TimestampTz,
                PrimitiveTypes.TimestampNs, PrimitiveTypes.TimestampTzNs, 
PrimitiveTypes.String,
-               PrimitiveTypes.Binary, PrimitiveTypes.UUID, FixedTypeOf(16), 
DecimalTypeOf(10, 2),
+               PrimitiveTypes.Binary, PrimitiveTypes.UUID, 
MustFixedTypeOf(16), MustDecimalTypeOf(10, 2),
        } {
                t.Run(typ.String(), func(t *testing.T) {
                        bound, err := Extract("payload", "$.a", 
typ).Bind(schema, true)
diff --git a/visitors_test.go b/visitors_test.go
index 96a7992b8..ce5cb82ba 100644
--- a/visitors_test.go
+++ b/visitors_test.go
@@ -410,7 +410,7 @@ func TestTranslateColumnNamesMissingFieldInitialDefault(t 
*testing.T) {
                {
                        name: "matching fixed metadata default",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "missing_col", Type: 
iceberg.FixedTypeOf(3),
+                               ID: 2, Name: "missing_col", Type: 
iceberg.MustFixedTypeOf(3),
                                InitialDefault: "010203",
                        },
                        expr:     iceberg.EqualTo(ref, []byte{1, 2, 3}),
@@ -428,7 +428,7 @@ func TestTranslateColumnNamesMissingFieldInitialDefault(t 
*testing.T) {
                {
                        name: "matching native byte default",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "missing_col", Type: 
iceberg.FixedTypeOf(3),
+                               ID: 2, Name: "missing_col", Type: 
iceberg.MustFixedTypeOf(3),
                                InitialDefault: []byte{1, 2, 3},
                        },
                        expr:     iceberg.EqualTo(ref, []byte{1, 2, 3}),
@@ -482,7 +482,7 @@ func TestTranslateColumnNamesMissingFieldInitialDefault(t 
*testing.T) {
                {
                        name: "matching decimal metadata default",
                        field: iceberg.NestedField{
-                               ID: 2, Name: "missing_col", Type: 
iceberg.DecimalTypeOf(9, 2),
+                               ID: 2, Name: "missing_col", Type: 
iceberg.MustDecimalTypeOf(9, 2),
                                InitialDefault: "12.34",
                        },
                        expr:     iceberg.EqualTo(ref, "12.34"),
@@ -1093,11 +1093,11 @@ func TestEvaluatorCmpTypes(t *testing.T) {
                iceberg.NestedField{ID: 6, Name: "f", Type: 
iceberg.PrimitiveTypes.Date},
                iceberg.NestedField{ID: 7, Name: "g", Type: 
iceberg.PrimitiveTypes.Time},
                iceberg.NestedField{ID: 8, Name: "h", Type: 
iceberg.PrimitiveTypes.Timestamp},
-               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.DecimalTypeOf(9, 2)},
+               iceberg.NestedField{ID: 9, Name: "i", Type: 
iceberg.MustDecimalTypeOf(9, 2)},
                iceberg.NestedField{ID: 10, Name: "j", Type: 
iceberg.PrimitiveTypes.String},
                iceberg.NestedField{ID: 11, Name: "k", Type: 
iceberg.PrimitiveTypes.Binary},
                iceberg.NestedField{ID: 12, Name: "l", Type: 
iceberg.PrimitiveTypes.UUID},
-               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.FixedTypeOf(5)},
+               iceberg.NestedField{ID: 13, Name: "m", Type: 
iceberg.MustFixedTypeOf(5)},
                iceberg.NestedField{ID: 14, Name: "n", Type: 
iceberg.PrimitiveTypes.TimestampNs},
                iceberg.NestedField{ID: 15, Name: "o", Type: 
iceberg.PrimitiveTypes.TimestampTzNs})
 
diff --git a/website/src/releases.md b/website/src/releases.md
index 636056764..4364cda9a 100644
--- a/website/src/releases.md
+++ b/website/src/releases.md
@@ -42,6 +42,7 @@ Per-release notes (highlights, breaking changes, 
contributors) are published on
 
 ### Unreleased compatibility notes
 
+- **Fixed and decimal constructors return errors.** `iceberg.FixedTypeOf` and 
`iceberg.DecimalTypeOf` now return `(type, error)` instead of panicking for 
invalid inputs. Use `MustFixedTypeOf` or `MustDecimalTypeOf` only for 
known-valid values.
 - **SQL UDF representations now use struct literals.** The 
`udf.NewSQLRepresentation(dialect, sql)` function, available since v0.7.0, is 
removed. Use `udf.SQLRepresentation{Dialect: "trino", SQL: "x + 1"}` instead. 
Empty fields and duplicate dialects are checked during metadata validation; 
serialized JSON is unchanged.
 - **Filesystem adapter construction consolidated.** Replace 
`io.FSPreProcName(fsys, fn)` with `io.FS(fsys, io.WithNamePreprocessor(fn))`. 
Plain `io.FS(fsys)` remains supported.
 - **Table purge is required on catalogs.** The `catalog.Catalog` interface now 
embeds `catalog.PurgeableCatalog`; every custom catalog implementation must 
provide `PurgeTable(ctx, identifier) error`. The narrow 
`catalog.PurgeableTable` interface is renamed to `catalog.PurgeableCatalog`. 
Built-in purge behavior is unchanged.

Reply via email to