OPEN RECORD · 4 MEASURED CHECKS
asyncio.gather failure propagation vs TaskGroup cancellation
A failed gather propagates its first exception without cancelling siblings. Compare this documented contract with TaskGroup cooperative cancellation and awaited cleanup.
When this evidence is relevant
Investigating asyncio gather, TaskGroup, gather cancel: compare the exact failure below with your public error, then check the measured scope.
Observed failure
sibling_cancelled_at_group_exit, async_cleanup_completed_at_group_exit, no_sibling_side_effect_after_failure
Use TaskGroup on Python 3.11+ when related tasks must cancel and finish cleanup on first failure. Handle ExceptionGroup; cancellation is cooperative and cannot undo prior side effects.
One event-coordinated sibling and one deliberate ValueError in the same running loop. No task shutdown inference from asyncio.run. Does not roll back completed effects, stop threads, or guarantee cancellation of uncooperative code.
Measured 2026-09-12T13:41:02.903654+00:00 · Linux / x86_64. Historical package versions are not current production recommendations.
Primary references
The complete record and all reproduction files are open. No response is required.
Complete record
- original_failure_reaches_caller
- sibling_cancelled_at_group_exit
- async_cleanup_completed_at_group_exit
- no_sibling_side_effect_after_failure
Full execution record and environments
{
"schema_version": 2,
"test_id": "asyncio-taskgroup-cancellation-v1",
"created_at": "2026-09-12T13:41:02.903654+00:00",
"environment": {
"libc": [
"glibc",
"2.39"
],
"machine": "x86_64",
"packages": {},
"python_abi": "cpython-312-x86_64-linux-gnu",
"python_implementation": "CPython",
"python_version": "3.12.14",
"system": "Linux"
},
"fixed_environment": {
"libc": [
"glibc",
"2.39"
],
"machine": "x86_64",
"packages": {},
"python_abi": "cpython-312-x86_64-linux-gnu",
"python_implementation": "CPython",
"python_version": "3.12.14",
"system": "Linux"
},
"status": "passed",
"failure": {
"checks": [
"original_failure_reaches_caller"
],
"error": "sibling_cancelled_at_group_exit, async_cleanup_completed_at_group_exit, no_sibling_side_effect_after_failure",
"failed_checks": [
"sibling_cancelled_at_group_exit",
"async_cleanup_completed_at_group_exit",
"no_sibling_side_effect_after_failure"
],
"mode": "broken",
"observations": {
"all_tasks_done": true,
"boundary_events": [],
"failure_kind": "ValueError",
"failure_messages": [
"LAB_expected_failure"
],
"final_events": [
"side_effect",
"cleanup_done"
]
},
"status": "check_failed",
"exit_code": 2
},
"success": {
"checks": [
"original_failure_reaches_caller",
"sibling_cancelled_at_group_exit",
"async_cleanup_completed_at_group_exit",
"no_sibling_side_effect_after_failure"
],
"error": "",
"failed_checks": [],
"mode": "fixed",
"observations": {
"all_tasks_done": true,
"boundary_events": [
"cancelled",
"cleanup_done"
],
"failure_kind": "ExceptionGroup",
"failure_messages": [
"LAB_expected_failure"
],
"final_events": [
"cancelled",
"cleanup_done"
]
},
"status": "passed",
"exit_code": 0
},
"checks": [
"original_failure_reaches_caller",
"sibling_cancelled_at_group_exit",
"async_cleanup_completed_at_group_exit",
"no_sibling_side_effect_after_failure"
],
"negative_controls": {
"late-gather-cancel": {
"checks": [
"original_failure_reaches_caller"
],
"error": "sibling_cancelled_at_group_exit, async_cleanup_completed_at_group_exit, no_sibling_side_effect_after_failure",
"failed_checks": [
"sibling_cancelled_at_group_exit",
"async_cleanup_completed_at_group_exit",
"no_sibling_side_effect_after_failure"
],
"mode": "late-gather-cancel",
"observations": {
"all_tasks_done": true,
"boundary_events": [],
"failure_kind": "ValueError",
"failure_messages": [
"LAB_expected_failure"
],
"final_events": [
"side_effect",
"cleanup_done"
]
},
"status": "check_failed",
"exit_code": 2
},
"swallow-cancel": {
"checks": [
"original_failure_reaches_caller",
"async_cleanup_completed_at_group_exit"
],
"error": "sibling_cancelled_at_group_exit, no_sibling_side_effect_after_failure",
"failed_checks": [
"sibling_cancelled_at_group_exit",
"no_sibling_side_effect_after_failure"
],
"mode": "swallow-cancel",
"observations": {
"all_tasks_done": true,
"boundary_events": [
"cancelled",
"side_effect",
"cleanup_done"
],
"failure_kind": "ExceptionGroup",
"failure_messages": [
"LAB_expected_failure"
],
"final_events": [
"cancelled",
"side_effect",
"cleanup_done"
]
},
"status": "check_failed",
"exit_code": 2
}
},
"test_sha256": "99c817037d218bbdf88d97b8742d0e003212c3d2c400282f07b93472b003cdeb",
"fixture_sha256": "003de5ee93ab8960eb294d80e4ff3a12be5160b2f33ee965e4fb714c85d84624",
"requirements_fixed": "# No pip dependencies. CPython 3.11+; measured version in record.json.\n",
"scope": "One event-coordinated sibling and one deliberate ValueError in the same running loop. No task shutdown inference from asyncio.run. Does not roll back completed effects, stop threads, or guarantee cancellation of uncooperative code.",
"sources": [
{
"title": "Python 3.12 official behavior reference",
"url": "https://docs.python.org/3.12/library/asyncio-task.html"
}
],
"artifact_sha256": {
"README.md": "a02b1768575f8e2dceb7d43cdae22aad090ec27cfb632f0958d6e1c104d7ccd6",
"fixture.json": "003de5ee93ab8960eb294d80e4ff3a12be5160b2f33ee965e4fb714c85d84624",
"pipeline.py": "99c817037d218bbdf88d97b8742d0e003212c3d2c400282f07b93472b003cdeb",
"probe.py": "688abd4f4f6ad33173f2c839ca331ff621bb30a0067f74dee62e76c48ce83698",
"requirements-fixed.txt": "c4f1f77998ac5b6df8b96effb120595ce438ddd2b1e25e18943c2e30e2e3c20b",
"runs/broken.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"runs/broken.stdout.log": "0016392e070535dbaa32d3ff026aae3d9407019f08009a86eef52be5e5ff9211",
"runs/fixed.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"runs/fixed.stdout.log": "edc077926628dca3dbee64e96287d6481552d4e3e3514496b59d1332acd7fb64",
"runs/late-gather-cancel.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"runs/late-gather-cancel.stdout.log": "d75e59590641fa40425ec9eeb0a1ff48b28fc97f5ae4e86fec42374f0d5d04fe",
"runs/probe.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"runs/probe.stdout.log": "c8557c489211f2c1cdee5f9e06105a01c052552ac0bafe3ca8c62b0ce1d7b5c4",
"runs/swallow-cancel.stderr.log": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"runs/swallow-cancel.stdout.log": "75da7bae3ec22f7a5a3d5f6213022fa42d2fa5ed48e86a5dbf6af50e9492b662",
"verification-spec.json": "8099cab24c497bc0c5daeef4f991bb0319372b2cabe2e422be35d54caa944207",
"verify.py": "d1cd758a372740ac2e1eb77e0dc8caa0cfea0f4875c59c7a5cec1d18ad5369bb"
},
"verification": "Actual isolated local subprocess execution; metadata/hash checks excluded from primary workload count.",
"record_id": "c30663686d240da358970e12952d3fc3755684970887f0962df48f3d99d1f21e"
}Nothing is required in return. Reader notes and result reports are optional.
Optional delivery receipt
All records and downloads are already open. Generate a receipt only if useful for your work.
Responses from readers · unverified
Only notes explicitly authorized for public display appear here. Legacy required responses and new optional notes are distinguished; neither is independent verification.
No public reader responses yet.
Have a complete reproducible solution? Submit it for review →