apache/iceberg · error · UnsupportedOperationException
hash(value) is not supported on the base Bucket class
Error message
hash(value) is not supported on the base Bucket class
What it means
Bucket<T> is an abstract base; actual hashing is implemented by per-type subclasses (BucketInt, BucketString, etc.) and reached through bind(type), which returns the type-specific function. Calling the protected hash(value) on the base class means no concrete type was bound, so Iceberg throws UnsupportedOperationException. Always obtain a bound function via bind() before hashing or applying.
Source
Thrown at api/src/main/java/org/apache/iceberg/transforms/Bucket.java:99
private final int numBuckets;
private Bucket(int numBuckets) {
this.numBuckets = numBuckets;
}
public Integer numBuckets() {
return numBuckets;
}
@Override
public SerializableFunction<T, Integer> bind(Type type) {
Preconditions.checkArgument(canTransform(type), "Cannot bucket by type: %s", type);
return get(type, numBuckets);
}
protected int hash(T value) {
throw new UnsupportedOperationException(
"hash(value) is not supported on the base Bucket class");
}
/**
* Transforms a value to its corresponding partition value.
*
* @param value a source value
* @return a transformed partition value
* @deprecated will be removed in 2.0.0; use {@link #bind(Type)} instead
*/
@Deprecated
@Override
public Integer apply(T value) {
if (value == null) {
return null;
}
return (hash(value) & Integer.MAX_VALUE) % numBuckets;
}View on GitHub (pinned to 86d9c8fc54)
Solutions
- Call bucketTransform.bind(type) and use the returned SerializableFunction to hash/apply values.
- Subclass Bucket for a concrete type and override hash() if you need custom behavior.
- Refactor code to never invoke the protected hash() on the base type.
Example fix
// before
Bucket<String> bucket = (Bucket<String>) Bucket.get(Types.StringType.get(), 8);
int h = bucket.hash("abc");
// after
SerializableFunction<String, Integer> fn =
Bucket.get(Types.StringType.get(), 8).bind(Types.StringType.get());
int h = fn.apply("abc"); Defensive patterns
Strategy: type-guard
Type guard
if (fn instanceof Bucket && fn.getClass() == Bucket.class) { throw new IllegalStateException("Bucket is not bound; call bind(type) first"); } Try / catch
try { return boundFn.apply(value); } catch (UnsupportedOperationException e) { throw new IllegalStateException("Use the function returned by bind(type), not the base Bucket", e); } Prevention
- Always call bind(type) and use the returned SerializableFunction
- Never invoke protected hash() from outside subclasses
- Add tests that hash via the bound function for each type
When it happens
Trigger: Invoking hash() directly on a raw Bucket<T> instance instead of the SerializableFunction returned by Bucket.bind(type); calling apply on an unbound generic Bucket.
Common situations: Custom transform/visitor code extending or instantiating Bucket directly; reflection-based utilities reaching into the base class; tests exercising hash paths (testTimestampNanoPromotion, testTimestampTzNanoPromotion) on the base class.
Related errors
- Unsupported time unit:
- Bucket transform is not supported
- Can't retrieve values from an empty struct
- Can't modify an empty struct
- %s doesn't implement cleanupLevel
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/9a8a1142d560aab2.
Report an issue: GitHub.