amoghrajesh opened a new pull request, #70513:
URL: https://github.com/apache/airflow/pull/70513
<!-- SPDX-License-Identifier: Apache-2.0
https://www.apache.org/licenses/LICENSE-2.0 -->
<!--
Thank you for contributing!
Please provide above a brief description of the changes made in this pull
request.
Write a good git commit message following this guide:
https://chris.beams.io/posts/git-commit/
Please make sure that your code changes are covered with tests.
And in case of new features or big changes remember to adjust the
documentation.
For user-facing UI changes, please attach before/after screenshots (or a
short
screen recording) so reviewers can assess the visual impact.
Feel free to ping (in general) for the review if you do not see reaction for
a few days
(72 Hours is the minimum reaction time you can expect from volunteers) - we
sometimes miss notifications.
In case of an existing issue, reference it using one of the following:
* closes: #ISSUE
* related: #ISSUE
-->
---
##### Was generative AI tooling used to co-author this PR?
<!--
If generative AI tooling has been used in the process of authoring this PR,
please
change below checkbox to `[X]` followed by the name of the tool, uncomment
the "Generated-by".
-->
- [ ] Yes (please specify the tool below)
<!--
Generated-by: [Tool Name] following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
-->
Related to https://github.com/apache/airflow/pull/70178
The previous fix kept a rolling tail of the last 20 lines of spark-submit's
own output, but deep JVM stack traces (Fabric8/Vert.x/Netty chains routinely
run 70+ lines through nested `Caused by:` blocks) pushed the real exception
message out of the buffer before the process finished, leaving only bare
stack frames with no message text. A live K8s quota rejection test reproduced
this exactly: the LLM retry policy saw only Netty I/O frames and misclassified
a permanent quota error as a transient SSL issue.
Anchor capture on the JVM's own uncaught-exception marker (`Exception in
thread "..."`) instead of a blind line count. Everything before the marker is
noise (banners, WARN logs) and is dropped; everything from the marker onward is
kept, with a generous safety-valve cap rather than a tight rolling window. If
`spark-submit` never throws an uncaught exception,
nothing is captured and the failure message carries no log tail, rather than
a plain last-N tail of possibly-irrelevant output.
### Testing
Error thrown now:
```shell
2026-07-27 15:35:25] ERROR - Task failed with exception
AirflowException: Cannot execute: spark-submit --master
k8s://https://host.docker.internal:6445 --conf
spark.kubernetes.container.image=apache/spark:3.5.3 --conf
spark.kubernetes.authenticate.driver.serviceAccountName=spark --conf
spark.driver.extraJavaOptions=-Djavax.net.ssl.trustAll=true --conf
spark.executor.extraJavaOptions=-Djavax.net.ssl.trustAll=true --conf
spark.kubernetes.submission.waitAppCompletion=false --conf
spark.kubernetes.namespace=spark --name arrow-spark --class
org.apache.spark.examples.SparkPi --deploy-mode cluster
local:///opt/spark/examples/jars/spark-examples_2.12-3.5.3.jar 100. Error code
is: 1. Kubernetes spark exit code is: None
Last spark-submit output:
Exception in thread "main"
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: POST
at: https://host.docker.internal:6445/api/v1/namespaces/spark/pods. Message:
pods "arrow-spark-5808b09fa309515b-driver" is forbidden: exceeded quota:
spark-demo-quota, requested: count/pods=1, used: count/pods=3, limited:
count/pods=3. Received status: Status(apiVersion=v1, code=403,
details=StatusDetails(causes=[], group=null, kind=pods,
name=arrow-spark-5808b09fa309515b-driver, retryAfterSeconds=null, uid=null,
additionalProperties={}), kind=Status, message=pods
"arrow-spark-5808b09fa309515b-driver" is forbidden: exceeded quota:
spark-demo-quota, requested: count/pods=1, used: count/pods=3, limited:
count/pods=3, metadata=ListMeta(_continue=null, remainingItemCount=null,
resourceVersion=null, selfLink=null, additionalProperties={}),
reason=Forbidden, status=Failure, additionalProperties={}).
at
io.fabric8.kubernetes.client.KubernetesClientException.copyAsCause(KubernetesClientException.java:205)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.waitForResult(OperationSupport.java:507)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.handleResponse(OperationSupport.java:524)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.handleCreate(OperationSupport.java:340)
at
io.fabric8.kubernetes.client.dsl.internal.BaseOperation.handleCreate(BaseOperation.java:766)
at
io.fabric8.kubernetes.client.dsl.internal.BaseOperation.handleCreate(BaseOperation.java:98)
at
io.fabric8.kubernetes.client.dsl.internal.CreateOnlyResourceOperation.create(CreateOnlyResourceOperation.java:42)
at
io.fabric8.kubernetes.client.dsl.internal.BaseOperation.create(BaseOperation.java:1167)
at
io.fabric8.kubernetes.client.dsl.internal.BaseOperation.create(BaseOperation.java:98)
at
org.apache.spark.deploy.k8s.submit.Client.run(KubernetesClientApplication.scala:154)
at
org.apache.spark.deploy.k8s.submit.KubernetesClientApplication.$anonfun$run$6(KubernetesClientApplication.scala:258)
at
org.apache.spark.deploy.k8s.submit.KubernetesClientApplication.$anonfun$run$6$adapted(KubernetesClientApplication.scala:252)
at
org.apache.spark.util.SparkErrorUtils.tryWithResource(SparkErrorUtils.scala:51)
at
org.apache.spark.util.SparkErrorUtils.tryWithResource$(SparkErrorUtils.scala:48)
at org.apache.spark.util.Utils$.tryWithResource(Utils.scala:97)
at
org.apache.spark.deploy.k8s.submit.KubernetesClientApplication.run(KubernetesClientApplication.scala:252)
at
org.apache.spark.deploy.k8s.submit.KubernetesClientApplication.start(KubernetesClientApplication.scala:225)
at
org.apache.spark.deploy.SparkSubmit.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:1033)
at org.apache.spark.deploy.SparkSubmit.doRunMain$1(SparkSubmit.scala:203)
at org.apache.spark.deploy.SparkSubmit.submit(SparkSubmit.scala:226)
at org.apache.spark.deploy.SparkSubmit.doSubmit(SparkSubmit.scala:95)
at
org.apache.spark.deploy.SparkSubmit$$anon$2.doSubmit(SparkSubmit.scala:1171)
at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:1180)
at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: io.fabric8.kubernetes.client.KubernetesClientException: Failure
executing: POST at:
https://host.docker.internal:6445/api/v1/namespaces/spark/pods. Message: pods
"arrow-spark-5808b09fa309515b-driver" is forbidden: exceeded quota:
spark-demo-quota, requested: count/pods=1, used: count/pods=3, limited:
count/pods=3. Received status: Status(apiVersion=v1, code=403,
details=StatusDetails(causes=[], group=null, kind=pods,
name=arrow-spark-5808b09fa309515b-driver, retryAfterSeconds=null, uid=null,
additionalProperties={}), kind=Status, message=pods
"arrow-spark-5808b09fa309515b-driver" is forbidden: exceeded quota:
spark-demo-quota, requested: count/pods=1, used: count/pods=3, limited:
count/pods=3, metadata=ListMeta(_continue=null, remainingItemCount=null,
resourceVersion=null, selfLink=null, additionalProperties={}),
reason=Forbidden, status=Failure, additionalProperties={}).
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:642)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.requestFailure(OperationSupport.java:622)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.assertResponseCode(OperationSupport.java:582)
at
io.fabric8.kubernetes.client.dsl.internal.OperationSupport.lambda$handleResponse$0(OperationSupport.java:549)
at
java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:646)
at
java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at
java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
at
io.fabric8.kubernetes.client.http.StandardHttpClient.lambda$completeOrCancel$10(StandardHttpClient.java:141)
at
java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at
java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at
java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at
java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
at
io.fabric8.kubernetes.client.http.ByteArrayBodyHandler.onBodyDone(ByteArrayBodyHandler.java:51)
at
java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at
java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:841)
at
java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at
java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2147)
at
io.fabric8.kubernetes.client.vertx.VertxHttpRequest.lambda$consumeBytes$1(VertxHttpRequest.java:84)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:252)
at
io.vertx.core.http.impl.HttpEventHandler.handleEnd(HttpEventHandler.java:76)
at
io.vertx.core.http.impl.HttpClientResponseImpl.handleEnd(HttpClientResponseImpl.java:250)
at
io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.lambda$new$0(Http1xClientConnection.java:448)
at
io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:279)
at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:157)
at
io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.handleEnd(Http1xClientConnection.java:758)
at io.vertx.core.impl.ContextImpl.execute(ContextImpl.java:327)
at io.vertx.core.impl.ContextImpl.execute(ContextImpl.java:307)
at
io.vertx.core.http.impl.Http1xClientConnection.handleResponseEnd(Http1xClientConnection.java:989)
at
io.vertx.core.http.impl.Http1xClientConnection.handleHttpMessage(Http1xClientConnection.java:861)
at
io.vertx.core.http.impl.Http1xClientConnection.handleMessage(Http1xClientConnection.java:823)
at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:159)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:153)
at
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at
io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:434)
at
io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:361)
at
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:325)
at
io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:249)
at
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1526)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1384)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1435)
at
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:545)
at
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:484)
at
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429)
at
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918)
at
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:176)
at
io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445)
at
io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:388)
at
io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:596)
at
io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:571)
at
io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:512)
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:484)
at
io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225)
at
io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196)
at
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1195)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 1593 in run
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 195 in wrapper
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 2178 in _execute_task
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 195 in wrapper
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 2136 in _run_execute_callable
File "/opt/airflow/task-sdk/src/airflow/sdk/bases/operator.py", line 445 in
wrapper
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/operators/spark_submit.py",
line 292 in execute
File "/opt/airflow/task-sdk/src/airflow/sdk/bases/resumablejobmixin.py",
line 200 in execute_resumable
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/operators/spark_submit.py",
line 309 in submit_job
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/hooks/spark_submit.py",
line 801 in submit
â–¶Post Execute
```
Earlier:
```shell
[2026-07-27 15:14:40] ERROR - Task failed with exception
AirflowException: Cannot execute: spark-submit --master
k8s://https://host.docker.internal:6445 --conf
spark.kubernetes.container.image=apache/spark:3.5.3 --conf
spark.kubernetes.authenticate.driver.serviceAccountName=spark --conf
spark.driver.extraJavaOptions=-Djavax.net.ssl.trustAll=true --conf
spark.executor.extraJavaOptions=-Djavax.net.ssl.trustAll=true --conf
spark.kubernetes.submission.waitAppCompletion=false --conf
spark.kubernetes.namespace=spark --name arrow-spark --class
org.apache.spark.examples.SparkPi --deploy-mode cluster
local:///opt/spark/examples/jars/spark-examples_2.12-3.5.3.jar 100. Error code
is: 1. Kubernetes spark exit code is: None
Last spark-submit output:
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1435)
at
io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:545)
at
io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:484)
at
io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
at
io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at
io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429)
at
io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918)
at
io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:176)
at
io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445)
at
io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:388)
at
io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:596)
at
io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:571)
at
io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:512)
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:484)
at
io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225)
at
io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196)
at
io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1195)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at
io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 1593 in run
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 195 in wrapper
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 2178 in _execute_task
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 195 in wrapper
File "/opt/airflow/task-sdk/src/airflow/sdk/execution_time/task_runner.py",
line 2136 in _run_execute_callable
File "/opt/airflow/task-sdk/src/airflow/sdk/bases/operator.py", line 445 in
wrapper
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/operators/spark_submit.py",
line 292 in execute
File "/opt/airflow/task-sdk/src/airflow/sdk/bases/resumablejobmixin.py",
line 200 in execute_resumable
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/operators/spark_submit.py",
line 309 in submit_job
File
"/opt/airflow/providers/apache/spark/src/airflow/providers/apache/spark/hooks/spark_submit.py",
line 797 in submit
```
---
* Read the **[Pull Request
Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)**
for more information. Note: commit author/co-author name and email in commits
become permanently public when merged.
* For fundamental code changes, an Airflow Improvement Proposal
([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvement+Proposals))
is needed.
* When adding dependency, check compliance with the [ASF 3rd Party License
Policy](https://www.apache.org/legal/resolved.html#category-x).
* For significant user-facing changes create newsfragment:
`{pr_number}.significant.rst`, in
[airflow-core/newsfragments](https://github.com/apache/airflow/tree/main/airflow-core/newsfragments).
You can add this file in a follow-up commit after the PR is created so you
know the PR number.
--
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]