You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2026/09/14 04:00:16 UTC

(spark-connect-swift) branch main updated: [SPARK-59483] Fix `DataFrame.(head|first)` to throw an error instead of crashing on empty results

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

dongjoon-hyun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/spark-connect-swift.git


The following commit(s) were added to refs/heads/main by this push:
     new e3427aa  [SPARK-59483] Fix `DataFrame.(head|first)` to throw an error instead of crashing on empty results
e3427aa is described below

commit e3427aac36b31c7f53d119c06563c7a10e17b8d1
Author: Dongjoon Hyun <do...@apache.org>
AuthorDate: Sun Sep 13 21:00:10 2026 -0700

    [SPARK-59483] Fix `DataFrame.(head|first)` to throw an error instead of crashing on empty results
    
    ### What changes were proposed in this pull request?
    
    This PR aims to fix `DataFrame.head()` and `first()` to throw `SparkConnectError.invalidState` instead of crashing on empty results.
    
    ### Why are the changes needed?
    
    Currently, `head()` and `first()` crash on an empty `DataFrame`.
    
    ```swift
    try await spark.range(0).head()  // Fatal error: Index out of range
    ```
    
    Apache Spark's `Dataset.head()` throws `NoSuchElementException: head of empty array` in this case ([v4.2.0](https://github.com/apache/spark/blob/v4.2.0/sql/api/src/main/scala/org/apache/spark/sql/Dataset.scala#L2786), 2026-07-11). This PR uses the same message.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No behavior change. Previously, `head()` and `first()` crashes and now they throw an error on an empty `DataFrame` . Both methods are already `async throws`, so this is source-compatible.
    
    ### How was this patch tested?
    
    Pass the CIs with the newly added test cases.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Claude Opus 5
    
    Closes #564 from dongjoon-hyun/SPARK-59483.
    
    Authored-by: Dongjoon Hyun <do...@apache.org>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 Sources/SparkConnect/DataFrame+Actions.swift |  8 +++++++-
 Tests/SparkConnectTests/DataFrameTests.swift | 10 ++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/Sources/SparkConnect/DataFrame+Actions.swift b/Sources/SparkConnect/DataFrame+Actions.swift
index 43e2a8b..974955b 100644
--- a/Sources/SparkConnect/DataFrame+Actions.swift
+++ b/Sources/SparkConnect/DataFrame+Actions.swift
@@ -306,12 +306,18 @@ extension DataFrame {
 
   /// Returns the first row.
   /// - Returns: A ``Row``.
+  /// - Throws: ``SparkConnectError/invalidState(_:)`` if this ``DataFrame`` is empty.
   public func head() async throws -> Row {
-    return try await head(1)[0]
+    guard let row = try await head(1).first else {
+      throw SparkConnectError.invalidState(
+        SparkConnectError.Details(message: "head of empty array"))
+    }
+    return row
   }
 
   /// Returns the first row. Alias for head().
   /// - Returns: A ``Row``.
+  /// - Throws: ``SparkConnectError/invalidState(_:)`` if this ``DataFrame`` is empty.
   public func first() async throws -> Row {
     return try await head()
   }
diff --git a/Tests/SparkConnectTests/DataFrameTests.swift b/Tests/SparkConnectTests/DataFrameTests.swift
index 53a9786..4d2c9d2 100644
--- a/Tests/SparkConnectTests/DataFrameTests.swift
+++ b/Tests/SparkConnectTests/DataFrameTests.swift
@@ -814,6 +814,11 @@ struct DataFrameTests {
     let spark = try await SparkSession.builder.getOrCreate()
     #expect(try await spark.range(2).sort("id").first() == Row(0))
     #expect(try await spark.range(2).sort("id").head() == Row(0))
+    let error = try await #require(throws: SparkConnectError.self) {
+      try await spark.range(0).first()
+    }
+    #expect(error == .InvalidState)
+    #expect(error.message == "head of empty array")
     await spark.stop()
   }
 
@@ -821,6 +826,11 @@ struct DataFrameTests {
   func head() async throws {
     let spark = try await SparkSession.builder.getOrCreate()
     #expect(try await spark.range(0).head(1).isEmpty)
+    let error = try await #require(throws: SparkConnectError.self) {
+      try await spark.range(0).head()
+    }
+    #expect(error == .InvalidState)
+    #expect(error.message == "head of empty array")
     #expect(try await spark.range(2).sort("id").head() == Row(0))
     #expect(try await spark.range(2).sort("id").head(1) == [Row(0)])
     #expect(try await spark.range(2).sort("id").head(2) == [Row(0), Row(1)])


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org