{"record":{"id":"9c6636e4c7aa85c4","repo":"jely2002/youtube-dl-gui","slug":"orphaned-media-item-found","errorCode":null,"errorMessage":"Orphaned media item found.","messagePattern":"Orphaned media item found\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/stores/media/media.ts","lineNumber":89,"sourceCode":"        return;\n      }\n      for (const newGroup of newGroups) {\n        stateStore.setGroupState(newGroup.id, MediaState.configure);\n      }\n    } else {\n      groupStore.consolidateGroup(group);\n      void notifyGroup(NotificationKind.PlaylistReady, group, {}, group.entries?.length ?? 1);\n      stateStore.setGroupState(group.id, MediaState.configure);\n      resolvePendingReadyGroup(group.id, [group.id]);\n    }\n  }\n\n  function processMediaAddPayload(payload: MediaAddPayload) {\n    const { item, groupId, total } = payload;\n    item.groupId = groupId;\n\n    const group = groupStore.findGroupById(groupId);\n    if (!group) throw new Error('Orphaned media item found.');\n\n    if (item.entries) {\n      const existingId = Object.keys(group.items)[0];\n      if (existingId && existingId !== item.id) {\n        delete group.items[existingId];\n      }\n\n      item.isLeader = true;\n      group.items[item.id] = item;\n      const { id, groupId: gid, isLeader, ...meta } = item;\n      void id;\n      void gid;\n      void isLeader;\n      Object.assign(group, meta);\n      group.total = total;\n      group.processed = 0;\n      if (group.skipPlaylistSelection) {\n        void expandPlaylistGroup(groupId, { rows: [] }).catch((error) => {","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/jely2002/youtube-dl-gui/blob/c402ee39c0eabab68934c48f8b787ff37a1577b0/src/stores/media/media.ts#L71-L107","documentation":"processMediaAddPayload attaches a newly added media item to its group. Before mutating group.items it verifies the group exists; if findGroupById returns undefined it throws 'Orphaned media item found.' The store requires every media item to belong to a live group.","triggerScenarios":"A MediaAddPayload event with a groupId that has no matching group — the group was deleted before the add payload arrived, the add event is replayed after the group list was cleared, or the backend and frontend group registries are out of sync.","commonSituations":"Rapid cancel/remove of a group during download start; stale WebSocket/Tauri events delivered after state reset; races between group teardown and queued add payloads.","solutions":["Verify the group is created (and present in groupOrder) before any media add payload for it can be processed.","Guard the caller: skip the payload if groupStore.findGroupById(groupId) is undefined.","Make group removal cancel/flush pending add events for that group first.","Add a try/catch around processMediaAddPayload to log and drop orphaned payloads instead of propagating."],"exampleFix":"// before\nfunction handleMediaAdd(payload: MediaAddPayload) {\n  processMediaAddPayload(payload);\n}\n// after\nfunction handleMediaAdd(payload: MediaAddPayload) {\n  if (!groupStore.findGroupById(payload.groupId)) return; // stale add payload\n  processMediaAddPayload(payload);\n}","handlingStrategy":"try-catch","validationCode":"if (!groupStore.findGroupById(payload.groupId)) return; // drop orphaned add payload","typeGuard":"const hasGroup = (groupId: string): boolean => groupStore.findGroupById(groupId) !== undefined;","tryCatchPattern":"try {\n  processMediaAddPayload(payload);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Orphaned media item')) {\n    console.warn('Dropped add event for missing group', payload.groupId);\n    return;\n  }\n  throw e;\n}","preventionTips":["Create the group before enqueueing any media add payloads for it.","Cancel pending events for a group before removing it.","Log-and-drop stale events in a single wrapper around event dispatch."],"tags":["state-management","pinia","orphaned-entity","race-condition"],"backgroundTag":"entity-not-found","analyzedSha":"c402ee39c0eabab68934c48f8b787ff37a1577b0","analyzedAt":"2026-09-12T02:01:12.452Z","contentChangedAt":"2026-09-12T02:01:12.452Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}