{"record":{"id":"89ff4c7ba75368c8","repo":"apache/iceberg","slug":"unsupported-runtime-filter-89ff4c","errorCode":null,"errorMessage":"Unsupported runtime filter {}","messagePattern":"Unsupported runtime filter (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkBatchQueryScan.java","lineNumber":208,"sourceCode":"    return ContentFileUtil.isFileScoped(deleteFile);\n  }\n\n  // at this moment, Spark can only pass IN filters for a single attribute\n  // if there are multiple filter attributes, Spark will pass two separate IN filters\n  private Expression convertRuntimeFilters(Predicate[] predicates) {\n    Expression runtimeFilterExpr = Expressions.alwaysTrue();\n\n    for (Predicate predicate : predicates) {\n      Expression expr = SparkV2Filters.convert(predicate);\n      if (expr != null) {\n        try {\n          Binder.bind(expectedSchema().asStruct(), expr, caseSensitive());\n          runtimeFilterExpr = Expressions.and(runtimeFilterExpr, expr);\n        } catch (ValidationException e) {\n          LOG.warn(\"Failed to bind {} to expected schema, skipping runtime filter\", expr, e);\n        }\n      } else {\n        LOG.warn(\"Unsupported runtime filter {}\", predicate);\n      }\n    }\n\n    return runtimeFilterExpr;\n  }\n\n  @Override\n  public Statistics estimateStatistics() {\n    if (scan() == null) {\n      return estimateStatistics(null);\n\n    } else if (snapshotId != null) {\n      Snapshot snapshot = table().snapshot(snapshotId);\n      return estimateStatistics(snapshot);\n\n    } else if (asOfTimestamp != null) {\n      long snapshotIdAsOfTime = SnapshotUtil.snapshotIdAsOfTime(table(), asOfTimestamp);\n      Snapshot snapshot = table().snapshot(snapshotIdAsOfTime);","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkBatchQueryScan.java#L190-L226","documentation":"SparkV2Filters.convert returned null because the runtime predicate kind is not representable as an Iceberg expression (unsupported function or literal type). SparkBatchQueryScan logs and skips that filter rather than failing the query. Performance-only impact: fewer predicates are pushed into the Iceberg scan.","triggerScenarios":"A Spark runtime filter using an unsupported predicate shape (e.g. certain functions, non-convertible literals) is applied to an Iceberg batch scan via SupportsRuntimeFiltering.filter([]).","commonSituations":"Spark versions emitting newer runtime filter functions than the connector supports; user-defined or non-standard filters; dynamic partition pruning variants not in Iceberg's supported set.","solutions":["No action needed for correctness; the filter is evaluated elsewhere in Spark.","Check which predicate was logged and whether it can be expressed as a supported Iceberg filter.","Upgrade the Iceberg Spark runtime to a version supporting the predicate."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"if (SparkV2Filters.convert(predicate) == null) { /* predicate unsupported; don't expect pushdown */ }","tryCatchPattern":null,"preventionTips":["Use only Iceberg-supported predicate kinds for filters you expect to be pushed.","Pin connector and Spark versions known to support your runtime filters.","Treat runtime filters as a performance-only optimization."],"tags":["spark","runtime-filter","pushdown","unsupported"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}