This is an automated email from the ASF dual-hosted git repository.
hvanhovell pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git
The following commit(s) were added to refs/heads/master by this push:
new 3298e685a964 [SPARK-55373][CONNECT] Improve noHandlerFoundForExtension
error message
3298e685a964 is described below
commit 3298e685a9641c3e137917f75f58bc0bcfdfe32e
Author: Alex Khakhlyuk <[email protected]>
AuthorDate: Thu Feb 5 10:45:46 2026 -0400
[SPARK-55373][CONNECT] Improve noHandlerFoundForExtension error message
### What changes were proposed in this pull request?
Spark Connect Planner supports extension fields for Relation, Command,
Expression protos. Extensions are processed through handlers. If a handler is
not available for a given extension type, the planner will throw this error:
```
org.apache.spark.sql.connect.common.InvalidPlanInput: [INTERNAL_ERROR] No
handler found for extension SQLSTATE: XX000
```
This error is not informative enough when debugging. I propose adding
extension proto type url to the error message which will make it clear which
extension is missing
```
org.apache.spark.sql.connect.common.InvalidPlanInput: [INTERNAL_ERROR] No
handler found for extension type:
type.googleapis.com/google.protobuf.StringValue SQLSTATE: XX000
```
### Why are the changes needed?
Improve debuggability of the `noHandlerFoundForExtension` exception.
### Does this PR introduce _any_ user-facing change?
Yes, `noHandlerFoundForExtension` will now contain the protobuf type url of
the missing unsupported extension. E.g. before:
```
org.apache.spark.sql.connect.common.InvalidPlanInput: [INTERNAL_ERROR] No
handler found for extension SQLSTATE: XX000
```
After:
```
org.apache.spark.sql.connect.common.InvalidPlanInput: [INTERNAL_ERROR] No
handler found for extension type:
type.googleapis.com/google.protobuf.StringValue SQLSTATE: XX000
```
### How was this patch tested?
New unit test
### Was this patch authored or co-authored using generative AI tooling?
No
Closes #54160 from khakhlyuk/improve-no-handler-found-for-extension.
Authored-by: Alex Khakhlyuk <[email protected]>
Signed-off-by: Herman van Hövell <[email protected]>
---
.../sql/connect/planner/InvalidInputErrors.scala | 5 +++--
.../sql/connect/planner/SparkConnectPlanner.scala | 6 +++---
.../connect/planner/SparkConnectPlannerSuite.scala | 21 ++++++++++++++++++++-
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git
a/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/InvalidInputErrors.scala
b/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/InvalidInputErrors.scala
index eb4df9673e59..81c001ed839f 100644
---
a/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/InvalidInputErrors.scala
+++
b/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/InvalidInputErrors.scala
@@ -30,8 +30,9 @@ import org.apache.spark.sql.types.DataType
object InvalidInputErrors {
- def noHandlerFoundForExtension(): InvalidPlanInput =
- InvalidPlanInput("No handler found for extension")
+ def noHandlerFoundForExtension(extensionTypeUrl: String): InvalidPlanInput =
{
+ InvalidPlanInput(s"No handler found for extension type: $extensionTypeUrl")
+ }
def invalidSQLWithReferences(query: proto.WithRelations): InvalidPlanInput =
InvalidPlanInput(s"$query is not a valid relation for SQL with references")
diff --git
a/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/SparkConnectPlanner.scala
b/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/SparkConnectPlanner.scala
index d47409d7e681..611e19b01b20 100644
---
a/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/SparkConnectPlanner.scala
+++
b/sql/connect/server/src/main/scala/org/apache/spark/sql/connect/planner/SparkConnectPlanner.scala
@@ -264,7 +264,7 @@ class SparkConnectPlanner(
.map(p => p.transform(extension.toByteArray, this))
// Find the first non-empty transformation or throw.
.find(_.isPresent)
- .getOrElse(throw InvalidInputErrors.noHandlerFoundForExtension())
+ .getOrElse(throw
InvalidInputErrors.noHandlerFoundForExtension(extension.getTypeUrl))
.get()
}
@@ -1948,7 +1948,7 @@ class SparkConnectPlanner(
.map(p => p.transform(extension.toByteArray, this))
// Find the first non-empty transformation or throw.
.find(_.isPresent)
- .getOrElse(throw InvalidInputErrors.noHandlerFoundForExtension())
+ .getOrElse(throw
InvalidInputErrors.noHandlerFoundForExtension(extension.getTypeUrl))
.get
}
@@ -3230,7 +3230,7 @@ class SparkConnectPlanner(
.map(p => p.process(extension.toByteArray, this))
// Find the first non-empty transformation or throw.
.find(_ == true)
- .getOrElse(throw InvalidInputErrors.noHandlerFoundForExtension())
+ .getOrElse(throw
InvalidInputErrors.noHandlerFoundForExtension(extension.getTypeUrl))
executeHolder.eventsManager.postFinished()
}
diff --git
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectPlannerSuite.scala
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectPlannerSuite.scala
index 66ff45b553c7..89ccaea93a04 100644
---
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectPlannerSuite.scala
+++
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectPlannerSuite.scala
@@ -19,7 +19,7 @@ package org.apache.spark.sql.connect.planner
import scala.jdk.CollectionConverters._
-import com.google.protobuf.ByteString
+import com.google.protobuf.{Any, ByteString, StringValue}
import org.apache.spark.SparkFunSuite
import org.apache.spark.connect.proto
@@ -1069,4 +1069,23 @@ class SparkConnectPlannerSuite extends SparkFunSuite
with SparkConnectPlanTest {
"23:59:59.999999999",
"23:59:59.999999999").toString)
}
+
+ test("No handler found for extension shows extension type URL - Relation
extension") {
+ val extension = StringValue
+ .newBuilder()
+ .setValue("unknown-relation")
+ .build()
+ val relation = proto.Relation
+ .newBuilder()
+ .setExtension(Any.pack(extension))
+ .build()
+
+ val intercepted = intercept[InvalidPlanInput] {
+ transform(relation)
+ }
+
+ assert(
+ intercepted.getMessage.contains("No handler found for extension type: " +
+ "type.googleapis.com/google.protobuf.StringValue"))
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]