Skip to content

Fix IndexError crash in work_process with multiple circular-descendant parents#5

Open
czxb7r wants to merge 1 commit into
MetaTunes:metabrainz/2.0from
czxb7r:fix-work_process-circular-parent-indexerror
Open

Fix IndexError crash in work_process with multiple circular-descendant parents#5
czxb7r wants to merge 1 commit into
MetaTunes:metabrainz/2.0from
czxb7r:fix-work_process-circular-parent-indexerror

Conversation

@czxb7r
Copy link
Copy Markdown

@czxb7r czxb7r commented May 29, 2026

Problem

Classical Extras crashes Picard (SIGABRT) while processing a release whose work hierarchy contains two or more circular parent references.

Reproduced with the work "Tannhäuser: Ouverture and Venusberg Music" (d801c361-fcfa-4485-81b4-486154daf6bd), which has two parents that are circular descendants. The plugin correctly logs Found parent which is descendant of child - not using, to prevent circular references (twice), then dies:

File "webservice/__init__.py", line 593, in _process_reply
File "webservice/__init__.py", line 578, in _handle_reply
File ".../classical_extras/__init__.py", line 4977, in work_process
IndexError: pop index out of range

Because this runs inside a QtNetwork reply slot, PyQt escalates the uncaught exception to qFatal()abort(), taking the whole app down (no Python traceback shown in the GUI; just a crash).

Observed on installed 2.0.14 and present on this branch (2.0.11).

Root cause

In PartLevels.work_process, the circular-parent removal collects indices into the parallel parentIds/parents lists in del_list, then removes them with:

for i in list(set(del_list)):
    removed_id = parentIds.pop(i)
    removed_name = parents.pop(i)

set iteration order is arbitrary, and each pop(i) shrinks the list, so once a second index is popped a later index is out of range. A single circular parent happens to work by luck; two or more reliably crash.

Fix

Pop in descending index order so earlier removals don't invalidate later indices — one line:

for i in sorted(set(del_list), reverse=True):

Testing

With this change the same release tags through cleanly, the two circular parents are still correctly dropped and reported via ~cwp_error, and no crash occurs.

Environment: Picard 2.13.3, Python 3.11.5, PyQt 5.15.11, macOS.

When a work has two or more parents that are circular descendants, the
removal loop iterated del_list via list(set(...)) (arbitrary order) and
called parentIds.pop(i)/parents.pop(i). Each pop shrinks the list, so a
later index becomes out of range -> IndexError: pop index out of range.
Because this runs inside a QtNetwork reply slot, PyQt escalates the
uncaught exception to qFatal()/abort() and Picard crashes.

Pop in descending index order so earlier removals do not invalidate
later indices.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant