Skip to content

Commit d4e00e4

Browse files
SNOW-3494628: Fix indeterministic error reporting for async job no_result (#4221)
1 parent 91f7657 commit d4e00e4

3 files changed

Lines changed: 37 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#### Bug Fixes
1010

11+
- Fixed a bug where `AsyncJob.result("no_result")` sometimes silently returned without raising error for failed queries.
12+
1113
#### Improvements
1214

1315
- When `Session.reduce_describe_query_enabled` is enabled, fewer DESCRIBE queries are issued when the outer query only projects or renames columns from an inner subquery whose column types are already known.

src/snowflake/snowpark/async_job.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ def result(
427427
# If we can advance in ASYNC_RETRY_PATTERN then do so
428428
if retry_pattern_pos < (len(ASYNC_RETRY_PATTERN) - 1):
429429
retry_pattern_pos += 1
430+
# Without this post-loop check, a failed query would silently return None.
431+
# The upstream `get_results_from_sfqid` only catches failures already visible
432+
# at that single synchronous status check, and no fetch happens in NO_RESULT mode
433+
# to trigger the prefetch hook.
434+
self._session.connection.get_query_status_throw_if_error(self.query_id)
430435
result = None
431436
elif async_result_type == _AsyncResultType.PANDAS:
432437
result = self._session._conn._to_data_or_iter(

tests/integ/scala/test_async_job_suite.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,36 @@ def test_create_async_job_negative(session):
457457
async_job.result()
458458

459459

460+
def test_async_job_no_result_raises_on_failed_query(session):
461+
# Warm the warehouse so that subsequent iterations are dominated by the race condition
462+
session.sql("select 1").collect()
463+
iterations = 30
464+
silent_none = 0
465+
raised = 0
466+
sample_exception_text = ""
467+
468+
for _ in range(iterations):
469+
async_job = session.sql("select 1/0").collect_nowait()
470+
try:
471+
async_job.result("no_result")
472+
silent_none += 1
473+
except (DatabaseError, SnowparkSQLException) as exc:
474+
raised += 1
475+
if not sample_exception_text:
476+
sample_exception_text = str(exc)
477+
478+
assert silent_none == 0, (
479+
f"AsyncJob.result('no_result') silently returned None for "
480+
f"{silent_none}/{iterations} failed division by zero queries. "
481+
"All failures must surface as exceptions"
482+
)
483+
assert raised == iterations
484+
assert (
485+
"Division by zero" in sample_exception_text
486+
or "FAILED_WITH_ERROR" in sample_exception_text
487+
), f"Unexpected exception text: {sample_exception_text!r}"
488+
489+
460490
@pytest.mark.skipif(IS_IN_STORED_PROC, reason="caplog is not supported")
461491
@pytest.mark.parametrize("create_async_job_from_query_id", [True, False])
462492
def test_get_query_from_async_job(session, create_async_job_from_query_id, caplog):

0 commit comments

Comments
 (0)