Skip to content

Commit 0523411

Browse files
committed
Handle corrupt archive errors from Conda extraction workers
1 parent 2bba05e commit 0523411

2 files changed

Lines changed: 35 additions & 11 deletions

File tree

conda_self/reset.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ def records_from_snapshot(
113113
nested_error = pending_errors.pop()
114114
if isinstance(nested_error, CondaMultiError):
115115
pending_errors.extend(nested_error.errors)
116+
elif type(nested_error) is RuntimeError and str(
117+
nested_error
118+
).startswith(
119+
f"{InvalidArchiveError.__module__}."
120+
f"{InvalidArchiveError.__qualname__}: "
121+
):
122+
# Conda 26.7 extraction workers wrap unpicklable errors in
123+
# RuntimeError, retaining only the qualified type and message.
124+
found_error = True
116125
elif not isinstance(
117126
nested_error, (CondaError, InvalidArchiveError)
118127
) or isinstance(nested_error, (CondaExitZero, CondaSignalInterrupt)):

tests/test_cli_reset.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,9 @@ def test_reset_snapshot_reinstalls_same_package_for_url_or_checksum_mismatch(
371371
assert snapshot_reset["diff"]["final_precs"] == (target,)
372372

373373

374-
def test_reset_snapshot_download_error_reports_safe_context(
374+
@pytest.mark.parametrize("worker_error", [False, True], ids=["download", "worker"])
375+
def test_reset_snapshot_package_error_reports_safe_context(
376+
worker_error: bool,
375377
snapshot_reset: dict,
376378
tmp_path: Path,
377379
):
@@ -386,17 +388,20 @@ def test_reset_snapshot_download_error_reports_safe_context(
386388
)
387389
snapshot = tmp_path / "snapshot.explicit.txt"
388390
snapshot.write_text(f"@EXPLICIT\n{explicit_entry(unavailable)}\n")
389-
snapshot_reset["fetch_error"] = CondaMultiError(
390-
(
391-
CondaHTTPError(
392-
"server%body-secret",
393-
f"{unavailable.url}?X-Amz-Credential=signed-secret",
394-
404,
395-
"reason%secret",
396-
"-",
397-
),
398-
)
391+
error: Exception = CondaHTTPError(
392+
"server%body-secret",
393+
f"{unavailable.url}?X-Amz-Credential=signed-secret",
394+
404,
395+
"reason%secret",
396+
"-",
399397
)
398+
if worker_error:
399+
error = RuntimeError(
400+
"conda_package_handling.exceptions.InvalidArchiveError: "
401+
f"archive from {unavailable.url}?X-Amz-Credential=signed-secret "
402+
"server%body-secret reason%secret"
403+
)
404+
snapshot_reset["fetch_error"] = CondaMultiError((error,))
400405

401406
with pytest.raises(CondaError) as exc_info:
402407
reset(prefix="/target", snapshot=snapshot)
@@ -440,6 +445,15 @@ def test_reset_snapshot_download_error_reports_safe_context(
440445
CondaMultiError((CondaMultiError((CondaExitZero("requested exit"),)),)),
441446
CondaMultiError((CondaMultiError((RuntimeError("unexpected failure"),)),)),
442447
CondaMultiError((CondaMultiError((CondaSignalInterrupt(signal.SIGINT),)),)),
448+
CondaMultiError(
449+
(
450+
RuntimeError("unexpected failure"),
451+
RuntimeError(
452+
"conda_package_handling.exceptions.InvalidArchiveError: "
453+
"corrupt archive"
454+
),
455+
)
456+
),
443457
],
444458
ids=[
445459
"exit",
@@ -449,6 +463,7 @@ def test_reset_snapshot_download_error_reports_safe_context(
449463
"nested-exit",
450464
"nested-unexpected",
451465
"nested-interrupt",
466+
"mixed-worker-and-unexpected",
452467
],
453468
)
454469
def test_reset_snapshot_preserves_interrupt_or_unexpected_error(

0 commit comments

Comments
 (0)