{"record":{"id":"713de8310ca2c224","repo":"apache/iceberg","slug":"does-not-support-caching","errorCode":null,"errorMessage":" does not support caching","messagePattern":" does not support caching","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java","lineNumber":96,"sourceCode":"   * to use the provided size as a guideline to decide whether the value is eligible for caching.\n   * For instance, it may be beneficial to discard values that are too large to optimize the cache\n   * performance and utilization.\n   */\n  protected boolean canCache(long size) {\n    return false;\n  }\n\n  /**\n   * Gets the cached value for the key or populates the cache with a new mapping.\n   *\n   * <p>If the value for the specified key is in the cache, it should be returned. If the value is\n   * not in the cache, implementations should compute the value using the provided supplier, cache\n   * it, and then return it.\n   *\n   * <p>This method will be called only if {@link #canCache(long)} returned true.\n   */\n  protected <V> V getOrLoad(String key, Supplier<V> valueSupplier, long valueSize) {\n    throw new UnsupportedOperationException(getClass().getName() + \" does not support caching\");\n  }\n\n  @Override\n  public StructLikeSet loadEqualityDeletes(Iterable<DeleteFile> deleteFiles, Schema projection) {\n    Iterable<Iterable<StructLike>> deletes =\n        execute(deleteFiles, deleteFile -> getOrReadEqDeletes(deleteFile, projection));\n    StructLikeSet deleteSet = StructLikeSet.create(projection.asStruct());\n    Iterables.addAll(deleteSet, Iterables.concat(deletes));\n    return deleteSet;\n  }\n\n  private Iterable<StructLike> getOrReadEqDeletes(DeleteFile deleteFile, Schema projection) {\n    long estimatedSize = estimateEqDeletesSize(deleteFile, projection);\n    if (canCache(estimatedSize)) {\n      String cacheKey = deleteFile.location();\n      return getOrLoad(cacheKey, () -> readEqDeletes(deleteFile, projection), estimatedSize);\n    } else {\n      return readEqDeletes(deleteFile, projection);","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java#L78-L114","documentation":"BaseDeleteLoader.getOrLoad is a hook for subclasses that implement delete-file caching; the base implementation does not cache and throws UnsupportedOperationException if called. It is only invoked after canCache(long) returned true, so calling this indicates a subclass claims caching support without implementing getOrLoad.","triggerScenarios":"A subclass of BaseDeleteLoader overrides canCache to return true but does not override getOrLoad; then getOrReadEqDeletes or indexes calls getOrLoad and hits the default throwing implementation.","commonSituations":"Custom delete loader implementations enabling caching incorrectly; copying a canCache override from another loader (e.g. a Spark cached loader) without the cache plumbing.","solutions":["Implement getOrLoad in your subclass with an actual cache (e.g. Caffeine) honoring valueSize","Return false from canCache if caching is not implemented","Use a built-in loader subclass that supports caching"],"exampleFix":"// before\n@Override\npublic boolean canCache(long contentSizeInBytes) {\n  return true; // but getOrLoad not implemented\n}\n// after\n@Override\npublic boolean canCache(long contentSizeInBytes) {\n  return cache != null && contentSizeInBytes <= maxEntrySize;\n}\n\n@Override\nprotected <V> V getOrLoad(String key, Supplier<V> valueSupplier, long valueSize) {\n  return cache.get(key, k -> valueSupplier.get());\n}","handlingStrategy":"validation","validationCode":"if (canCache(size) && getClass().getMethod(\"getOrLoad\", String.class, Supplier.class, long.class).getDeclaringClass() == BaseDeleteLoader.class) { throw new IllegalStateException(\"caching enabled without getOrLoad override\"); }","typeGuard":null,"tryCatchPattern":"try { loader.getOrLoad(key, supplier, size); } catch (UnsupportedOperationException e) { // fall back to uncached read }","preventionTips":["Never override canCache to return true without implementing getOrLoad","Unit-test custom delete loaders with caching enabled","Prefer built-in cached loader implementations over custom cache plumbing"],"tags":["caching","delete-loader","unimplemented-method","subclassing"],"backgroundTag":"method-not-implemented","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}