Connecting a signal to a Python lambda has no QObject receiver, so PySide6 treats it as a direct connection and runs the lambda on the emitting (worker) thread. The scrape dialog connected its results signals to lambdas, so _on_results/_on_scraped executed on the worker thread and called accept()/done() there -> QThread::wait on itself and GUI widget mutation off the GUI thread -> 'QThread: Destroyed while thread is still running' abort. Connect to bound methods (queued to the GUI thread) and carry the generation on the worker (read via sender().gen). Also replaced the thread.finished lambdas in load_library/metadata with bound-method cleanup keyed by a thread._worker attribute.