{"record":{"id":"74f19f9be50ab6e0","repo":"apache/iceberg","slug":"s-doesn-t-implement-cleanuplevel","errorCode":null,"errorMessage":"%s doesn't implement cleanupLevel","messagePattern":"(.+?) doesn't implement cleanupLevel","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/ExpireSnapshots.java","lineNumber":150,"sourceCode":"  ExpireSnapshots cleanExpiredFiles(boolean clean);\n\n  /**\n   * Configures the cleanup level for expired files.\n   *\n   * <p>This method provides fine-grained control over which files are cleaned up during snapshot\n   * expiration.\n   *\n   * <p>Consider {@link CleanupLevel#METADATA_ONLY} when data files are shared across tables or when\n   * using procedures like add-files that may reference the same data files.\n   *\n   * <p>Consider {@link CleanupLevel#NONE} when data and metadata files may be more efficiently\n   * removed using a distributed framework through the actions API.\n   *\n   * @param level the cleanup level to use for expired snapshots\n   * @return this for method chaining\n   */\n  default ExpireSnapshots cleanupLevel(CleanupLevel level) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" doesn't implement cleanupLevel\");\n  }\n\n  /**\n   * Enable cleaning up unused metadata, such as partition specs, schemas, etc.\n   *\n   * @param clean remove unused partition specs, schemas, or other metadata when true\n   * @return this for method chaining\n   */\n  default ExpireSnapshots cleanExpiredMetadata(boolean clean) {\n    throw new UnsupportedOperationException(\n        this.getClass().getName() + \" doesn't implement cleanExpiredMetadata\");\n  }\n}\n","sourceCodeStart":132,"sourceCodeEnd":165,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/ExpireSnapshots.java#L132-L165","documentation":"ExpireSnapshots.cleanupLevel is a default interface method that throws unless the concrete implementation supports choosing a cleanup level. The default exists so implementations predating CleanupLevel remain source-compatible; calling it on such an implementation surfaces this error naming the implementing class.","triggerScenarios":"Calling expireSnapshots.cleanupLevel(CleanupLevel.X) on an ExpireSnapshots implementation (e.g. an older catalog or third-party action) that has not overridden cleanupLevel.","commonSituations":"Mixing a newer Iceberg API client with an older engine/catalog implementation; custom ExpireSnapshots implementations that were not updated when CleanupLevel was introduced.","solutions":["Upgrade the implementation (Spark/Flink actions or custom class) to one that overrides cleanupLevel","Remove the cleanupLevel(...) call and rely on the implementation's default cleanup behavior","If you own the implementation, implement cleanupLevel to store and honor the CleanupLevel"],"exampleFix":"// before\nexpireSnapshots.cleanupLevel(CleanupLevel.LOCAL).execute();\n// after\nif (supportsCleanupLevel) {\n  expireSnapshots.cleanupLevel(CleanupLevel.LOCAL).execute();\n} else {\n  expireSnapshots.execute();\n}","handlingStrategy":"try-catch","validationCode":"// no pre-call capability flag exists; feature-gate by implementation type\nboolean supportsCleanupLevel = !(expireSnapshots.getClass().getName().startsWith(\"legacy.\"));","typeGuard":null,"tryCatchPattern":"try {\n  expireSnapshots.cleanupLevel(CleanupLevel.LOCAL);\n} catch (UnsupportedOperationException e) {\n  LOG.warn(\"cleanupLevel unsupported: {}\", e.getMessage());\n}","preventionTips":["Upgrade implementations before using newer ExpireSnapshots options","Feature-detect: attempt the call in a guarded path on startup","Keep custom ExpireSnapshots overrides in sync with the interface"],"tags":["java","api","unsupported-operation"],"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-14T11:17:12.474Z"}