You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(foundation): the pyshark engine raises a spurious TSharkCrashException on Python 3.9–3.12 #2633
extract(engine='pyshark') on Python 3.9–3.12 can raise a spurious TSharkCrashException: TShark (pid N) seems to have crashed (retcode: 255). It happens on roughly 1 in 15–40 extractions on a loaded host. #2620 found the cause, which is CPython gh-87744. That was fixed in 3.13 and never backported. asyncio's BaseSubprocessTransport.kill goes through Popen.kill → send_signal → poll(), which reaps a tshark that has already exited. SafeChildWatcher then logs Unknown child process pid N, will report returncode 255, and pyshark's close() raises. #2620 only makes the tests rerun; users are still exposed.
Needs deciding: the library-level mitigation.
In PyShark.close(), swallow a TSharkCrashException only when it reports retcode: 255 and the capture has reached EOF, then clear its _running_processes. A prototype ran 60 extractions with 0 failures. Risks: it depends on pyshark's message text and private attributes, it would hide a genuine tshark exit 255, and the real exit status stays lost.
Swap in ThreadedChildWatcher while the engine runs. A prototype gave 0 failures in 60. Risks: it changes process-global state, uses a deprecated API, and overrides pyshark's own choice.
Patch BaseSubprocessTransport.kill to signal with os.kill, as 3.13 does. This is a global monkeypatch of the stdlib.
Document the race and do nothing in the library.
Recommendation: 1, gated to 3.9–3.12. The fix touches only pcapkit's own engine, and the condition is narrow. Separately, pyshark could be asked upstream not to kill a tshark that has already reached EOF. Filing that is your call, since it posts to a third-party repository.
The owner chose 1, paraphrased: pcapkit's own PyShark.close() absorbs the spurious crash. The condition is kept as narrow as possible:
TSharkCrashException with retcode: 255;
the capture has already reached EOF;
Python 3.9–3.12.
Anything else still raises. The crashed capture is cleared so that its __del__ cannot raise later. The swallowed crash is logged at a handled level, not CRITICAL. A worker is on it. Nothing is filed upstream with pyshark.
A correction to the paraphrase above: in review of #2642, the owner then ruled that the absorption has no Python version gate. The merged fix (ce88220c0) applies on every Python, and the earlier 3.9–3.12 window survives only as background on why the status is lost.
Activity
JarryShaw commentedon Nov 2, 2026
Take 1
JarryShaw commentedon Nov 2, 2026
The owner chose 1, paraphrased: pcapkit's own
PyShark.close()absorbs the spurious crash. The condition is kept as narrow as possible:TSharkCrashExceptionwithretcode: 255;Anything else still raises. The crashed capture is cleared so that its
__del__cannot raise later. The swallowed crash is logged at a handled level, not CRITICAL. A worker is on it. Nothing is filed upstream with pyshark.fix(foundation): absorb the crash pyshark reports for a tshark asynci…
fix(foundation): absorb the crash pyshark reports for a tshark asynci…
fix(foundation): absorb the crash pyshark reports for a tshark asynci…
fix(foundation): absorb the crash pyshark reports for a tshark asynci…
fix(foundation): absorb the crash pyshark reports for a tshark asynci…
fix(foundation): absorb the crash pyshark reports for a tshark asynci…
JarryShaw commentedon Nov 2, 2026
A correction to the paraphrase above: in review of #2642, the owner then ruled that the absorption has no Python version gate. The merged fix (
ce88220c0) applies on every Python, and the earlier 3.9–3.12 window survives only as background on why the status is lost.test(foundation): build the real-poll child's engine before patching …