HyukjinKwon commented on code in PR #59219:
URL: https://github.com/apache/spark/pull/59219#discussion_r4216170281


##########
connector/kafka-0-10-sql/src/main/scala/org/apache/spark/sql/kafka010/KafkaSourceProvider.scala:
##########
@@ -374,13 +374,16 @@ private[kafka010] class KafkaSourceProvider extends 
DataSourceRegister
       STARTING_OFFSETS_OPTION_KEY, EarliestOffsetRangeLimit) match {
       case EarliestOffsetRangeLimit => // good to go
       case LatestOffsetRangeLimit =>
-        throw new IllegalArgumentException("starting offset can't be latest " +
-          "for batch queries on Kafka")
+        throw KafkaExceptions.invalidBatchOffset(

Review Comment:
   **Non-blocking (P2):** This now throws a `KafkaIllegalArgumentException` 
whose condition, `KAFKA_INVALID_BATCH_OFFSET.GLOBAL` or `.TOPIC_OR_PARTITION`, 
is defined only in the connector's `kafka-error-conditions.json`. Classic 
sessions get exactly the intended error. Spark Connect Scala clients do not.
   
   - The Connect server forwards the condition and parameters (`ErrorUtils`).
   - On the client, `GrpcExceptionConverter.errorsToThrowable` maps the 
`java.lang.IllegalArgumentException` hierarchy to `new 
SparkIllegalArgumentException(errorClass = ...)`.
   - That constructor re-renders the message through 
`SparkThrowableHelper.getMessage`, which reads only the core 
`error-conditions.json`.
   - `ErrorClassesJsonReader.getMessageTemplate` then throws `[INTERNAL_ERROR] 
Cannot find main error class 'KAFKA_INVALID_BATCH_OFFSET.GLOBAL'`. Nothing 
between that constructor and `convert` catches it.
   
   So on a Scala Connect client, 
`spark.read.format("kafka").option("startingOffsets", 
"latest")...load().collect()` (or `endingOffsets=earliest`, or a per-topic or 
per-partition JSON entry) fails with INTERNAL_ERROR (SQLSTATE XX000). Before 
this PR, these inputs carried no condition and reached the client as an 
`IllegalArgumentException` (legacy class `_LEGACY_ERROR_TEMP_3105`) with the 
actionable message. Now they lose the option name, the exception type, and the 
new 22023 SQLSTATE. Existing connector-only Kafka conditions, such as 
`KAFKA_DISALLOWED_OPTION`, already hit the same converter gap. This change 
extends it to a common misconfiguration, and the new tests run only in classic 
sessions.
   
   **Recommended change:** In the Spark Connect Scala client's exception 
converter, stop re-rendering a server condition that the client's error 
registry does not define. Build the mapped exception from the server-supplied 
message, keeping the server's errorClass, messageParameters, query context, and 
sqlState. Add a private[spark] message-preserving construction path on the 
affected Spark exception classes where one is not already reachable. Cover it 
with Connect client converter tests.
   
   **Why this works:** Gate the existing re-rendering constructors on 
SparkThrowableHelper.isValidErrorClass. Conditions known to the client keep 
today's construction. For an unknown condition, the converter uses the server 
message, which already contains the rendered text, so no registry lookup can 
throw. The exception stays an IllegalArgumentException (or the matching mapped 
type) and still reports KAFKA_INVALID_BATCH_OFFSET.* with SQLSTATE 22023.
   
   **Scope:** Connect client error reconstruction learns to fall back to the 
server-rendered message for conditions outside its local registry, with 
converter-level tests. The Kafka connector change stays as proposed.
   
   **Compatibility:** Client-side rendering of conditions defined in the core 
error registry, and the legacy-class fallback for errors without a condition, 
remain unchanged.
   
   **Risks:** A fallback that skips client-side rendering must not change 
messages for conditions the client already knows; gate strictly on registry 
membership. New private[spark] constructors must not collide with existing 
overloads or alter the Connect JVM client's checked binary surface.
   
   **Constraints:** Keep the server-supplied message as the source of truth for 
unknown conditions; do not rebuild it from possibly truncated parameters.
   
   **Success:** On a Scala Connect client, Kafka batch reads with 
startingOffsets=latest or endingOffsets=earliest (global, topic, or partition) 
fail with an IllegalArgumentException whose message names the option, condition 
KAFKA_INVALID_BATCH_OFFSET.GLOBAL or .TOPIC_OR_PARTITION, and SQLSTATE 22023, 
not INTERNAL_ERROR. Server conditions defined in the client's core registry, 
and errors without a condition, reconstruct exactly as before.
   
   **Verification:**
   - **Regression:** Converting a server error in the IllegalArgumentException 
hierarchy whose condition is absent from the client registry (with message 
parameters and sqlState 22023) yields an IllegalArgumentException carrying the 
server message, that condition, those parameters, and that SQLSTATE, with no 
internal error.
   - **Compatibility:** For every mapped exception type, a condition present in 
the core registry still renders client-side with the same message, condition, 
parameters, and SQLSTATE, and a missing condition still falls back to its 
legacy error class.
   - **Compile:** The common-utils and Connect client modules build, and the 
Connect JVM client's compatibility check still passes with the added 
construction path.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to