Qt 6.11 is out! See what's new in the release
blog
PySide6 6.11.1: QWebEngineUrlRequestJob.requestBody() causes SIGSEGV for POST requests to custom URL schemes
-
PySide6 QWebEngineUrlRequestJob.requestBody() causes SIGSEGV on POST requests to custom URL schemes
The crash happens immediately inside requestBody(), before accessing the returned object.
MRE
from __future__ import annotations import sys from PySide6 import __version__ as pyside6_ver from PySide6.QtCore import QByteArray, QBuffer, QIODevice, QTimer, QUrl, qVersion from PySide6.QtWebEngineCore import ( QWebEngineUrlScheme, QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob, QWebEngineProfile, ) print(f"Python: {sys.version}", flush=True) print(f"PySide6: {pyside6_ver}", flush=True) print(f"Qt: {qVersion()}", flush=True) scheme = QWebEngineUrlScheme(b"mre") scheme.setFlags( QWebEngineUrlScheme.Flag.SecureScheme | QWebEngineUrlScheme.Flag.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.Flag.FetchApiAllowed | QWebEngineUrlScheme.Flag.CorsEnabled ) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) QWebEngineUrlScheme.registerScheme(scheme) from PySide6.QtWidgets import QApplication from PySide6.QtWebEngineWidgets import QWebEngineView class Handler(QWebEngineUrlSchemeHandler): def requestStarted(self, job: QWebEngineUrlRequestJob) -> None: print( f"{job.requestMethod().data().decode()} {job.requestUrl().toString()}" ) print("before requestBody()", flush=True) job.requestBody() print("after requestBody()", flush=True) buf = QBuffer() buf.setData(b'{"ok":true}') buf.open(QIODevice.OpenModeFlag.ReadOnly) buf.setParent(job) job.reply(b"application/json", buf) app = QApplication(sys.argv) handler = Handler() QWebEngineProfile.defaultProfile().installUrlSchemeHandler( QByteArray(b"mre"), handler ) view = QWebEngineView() view.setHtml( """<!DOCTYPE html> <html><body> <p id="status">waiting...</p> <script> async function run() { try { document.getElementById('status').innerText = 'POST...'; r = await fetch('mre://test', {method: 'POST', body: '123'}); console.log('POST OK', await r.json()); //document.getElementById('status').innerText = 'GET...'; //let r = await fetch('mre://test', {method: 'GET'}); //console.log('GET OK', await r.json()); document.getElementById('status').innerText = 'Both OK'; } catch(e) { document.getElementById('status').innerText = e.toString(); } } setTimeout(run, 1500); </script> </body></html>""", baseUrl=QUrl("https://example.com/"), ) view.resize(600, 400) view.show() print("ready", flush=True) QTimer.singleShot(10000, app.quit) sys.exit(app.exec())/usr/bin/uv run /home/pyxiion/Projects/PxModRim/.venv/bin/python /home/pyxiion/Projects/PxModRim/mre_post_crash.py Python: 3.12.13 (main, Jun 11 2026, 04:03:26) [Clang 22.1.3 ] PySide6: 6.11.1 Qt: 6.11.1 ready POST mre://test/ before requestBody() Process finished with exit code 139 (interrupted by signal 11:SIGSEGV)PyQT
"""MRE: PyQt6 QWebEngineUrlSchemeHandler POST requestBody() crash""" from __future__ import annotations import sys from PyQt6.QtCore import QByteArray, QBuffer, QIODevice, QTimer, QUrl, qVersion from PyQt6.QtWebEngineCore import ( QWebEngineUrlScheme, QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob, QWebEngineProfile, ) from PyQt6 import QtCore print(f"PyQt6: {QtCore.PYQT_VERSION_STR}", flush=True) print(f"Qt: {qVersion()}", flush=True) # Register scheme before QApplication scheme = QWebEngineUrlScheme(b"mre") scheme.setFlags( QWebEngineUrlScheme.Flag.SecureScheme | QWebEngineUrlScheme.Flag.ContentSecurityPolicyIgnored | QWebEngineUrlScheme.Flag.FetchApiAllowed | QWebEngineUrlScheme.Flag.CorsEnabled ) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) QWebEngineUrlScheme.registerScheme(scheme) from PyQt6.QtWidgets import QApplication from PyQt6.QtWebEngineWidgets import QWebEngineView class Handler(QWebEngineUrlSchemeHandler): def requestStarted(self, job: QWebEngineUrlRequestJob) -> None: print( f"{job.requestMethod().data().decode()} {job.requestUrl().toString()}", file=sys.stderr, flush=True, ) print("before requestBody()", file=sys.stderr, flush=True) body = job.requestBody() print("after requestBody()", file=sys.stderr, flush=True) if body is not None: print(f" body obj: {body}", file=sys.stderr, flush=True) print(f" isOpen: {body.isOpen()}", file=sys.stderr, flush=True) if not body.isOpen(): body.open(QIODevice.OpenModeFlag.ReadOnly) raw = body.readAll().data() print(f" body ({len(raw)} bytes): {raw[:200]}", file=sys.stderr, flush=True) buf = QBuffer() buf.setData(b'{"ok":true}') buf.open(QIODevice.OpenModeFlag.ReadOnly) buf.setParent(job) job.reply(b"application/json", buf) app = QApplication(sys.argv) handler = Handler() QWebEngineProfile.defaultProfile().installUrlSchemeHandler( QByteArray(b"mre"), handler ) view = QWebEngineView() view.setHtml( """<!DOCTYPE html> <html><body> <p id="status">waiting...</p> <script> async function run() { try { document.getElementById('status').innerText = 'GET...'; let r = await fetch('mre://test', {method: 'GET'}); console.log('GET OK', await r.json()); document.getElementById('status').innerText = 'POST (empty body)...'; r = await fetch('mre://test', {method: 'POST'}); console.log('POST OK', await r.json()); document.getElementById('status').innerText = 'POST (with body)...'; r = await fetch('mre://test', {method: 'POST', body: JSON.stringify({hello:'world'})}); console.log('POST body OK', await r.json()); document.getElementById('status').innerText = 'All OK ✓'; } catch(e) { document.getElementById('status').innerText = e.toString(); } } setTimeout(run, 1500); </script> </body></html>""", baseUrl=QUrl("https://example.com/"), ) view.resize(600, 400) view.show() print("ready", file=sys.stderr, flush=True) QTimer.singleShot(10000, app.quit) sys.exit(app.exec())/usr/bin/uv run /home/pyxiion/Projects/RimSort/.venv/bin/python /home/pyxiion/Projects/RimSort/mre_post_crash_pyqt6.py PyQt6: 6.11.0 Qt: 6.11.1 ready GET mre://test/ before requestBody() after requestBody() body obj: <PyQt6.QtCore.QIODevice object at 0x7f251b2b6490> isOpen: False body (0 bytes): b'' POST mre://test/ before requestBody() after requestBody() body obj: <PyQt6.QtCore.QIODevice object at 0x7f251b2b6530> isOpen: False body (0 bytes): b'' POST mre://test/ before requestBody() after requestBody() body obj: <PyQt6.QtCore.QIODevice object at 0x7f251b2b6490> isOpen: False body (17 bytes): b'{"hello":"world"}' Process finished with exit code 0GDB bt
(gdb) bt #0 0x00007ffff73723ac in ?? () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.11 #1 0x00007ffff73730b8 in PySide::getWrapperForQObject(QObject*, _typeobject*) () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/libpyside6.abi3.so.6.11 #2 0x00007ffff618f22c in ?? () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/QtWebEngineCore.abi3.so #3 0x00000000018106c3 in cfunction_vectorcall_NOARGS.llvm.10372914493467373164 () #4 0x00000000018154f3 in _PyEval_EvalFrameDefault () #5 0x000000000181199a in method_vectorcall.llvm () #6 0x00007ffff6194c50 in ?? () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/QtWebEngineCore.abi3.so #7 0x00007ffff6194d0a in ?? () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/QtWebEngineCore.abi3.so #8 0x00007fffe8087dae in ?? () from /home/pyxiion/Projects/PxModRim/.venv/lib/python3.12/site-packages/PySide6/Qt/lib/libQt6WebEngineCore.so.6