{"record":{"id":"e892743207a7f2c4","repo":"jely2002/youtube-dl-gui","slug":"playlist-group-groupid-is-missing-entry-metadata","errorCode":null,"errorMessage":"Playlist group ${groupId} is missing entry metadata.","messagePattern":"Playlist group (.+?) is missing entry metadata\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/stores/media/media.ts","lineNumber":156,"sourceCode":"    if (group.processed === total) {\n      finalizePlaylistGroup(group);\n    } else if (group.total === 1 && !hasPlaylistLeader) {\n      void notifyGroup(NotificationKind.VideoReady, group);\n      resolvePendingReadyGroup(group.id, [group.id]);\n    }\n\n    const next = total > 1 && isFirst\n      ? MediaState.fetchingList\n      : MediaState.configure;\n    stateStore.setState(item.id, next);\n  }\n\n  async function expandPlaylistGroup(groupId: string, selection: PlaylistSelection) {\n    const group = groupStore.findGroupById(groupId);\n    const leader = groupStore.findGroupLeader(groupId);\n    const entries = group?.entries;\n    if (!group || !leader?.entries || !entries) {\n      throw new Error(`Playlist group ${groupId} is missing entry metadata.`);\n    }\n\n    const selectedEntries = applyPlaylistSelectionToEntries(entries, selection);\n    if (selectedEntries.length === 0) {\n      throw new Error('No playlist entries match the selected range.');\n    }\n    const spec = buildPlaylistItemsSpec(selection);\n    const previousOverrides = optionsStore.getOverrides(groupId);\n    const nextOverrides = cloneDownloadOverrides(previousOverrides) ?? {};\n\n    if (spec) {\n      nextOverrides.inputFilters = {\n        ...(nextOverrides.inputFilters ?? {}),\n        playlistItems: spec,\n      };\n    } else if (nextOverrides.inputFilters) {\n      delete nextOverrides.inputFilters.playlistItems;\n      if (Object.keys(nextOverrides.inputFilters).length === 0) {","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/jely2002/youtube-dl-gui/blob/c402ee39c0eabab68934c48f8b787ff37a1577b0/src/stores/media/media.ts#L138-L174","documentation":"expandPlaylistGroup resolves a playlist group, its leader item, and their entries metadata before expanding the playlist into individual items. If any of group, leader?.entries, or group.entries is missing, it throws 'Playlist group ${groupId} is missing entry metadata.' Playlists cannot be expanded without the entry list carried by the leader.","triggerScenarios":"Calling expandPlaylistGroup (directly or via processMediaAddPayload) for a groupId that is not a playlist group, whose leader item was deleted or replaced, or whose entries metadata was never populated by the backend.","commonSituations":"Passing a non-playlist (single media) group ID to the playlist expansion path; the leader item was removed by the de-duplication logic in processMediaAddPayload before expansion; backend produced a playlist group without entries metadata.","solutions":["Confirm the groupId refers to a playlist group whose leader item has an entries array before calling expand.","Check groupStore.findGroupLeader(groupId) and leader.entries in the caller and surface a user-facing 'not a playlist' message instead of throwing.","Ensure the backend payload that creates playlist groups always includes entries on both the group and the leader.","Catch the error where playlist selection is applied and show a toast asking the user to re-add the playlist."],"exampleFix":"// before\nawait expandPlaylistGroup(groupId, selection);\n// after\nconst leader = groupStore.findGroupLeader(groupId);\nif (!leader?.entries) {\n  console.warn(`Group ${groupId} is not an expandable playlist`);\n  return;\n}\nawait expandPlaylistGroup(groupId, selection);","handlingStrategy":"validation","validationCode":"const group = groupStore.findGroupById(groupId);\nconst leader = groupStore.findGroupLeader(groupId);\nif (!group || !leader?.entries || !group.entries) {\n  throw new Error(`Group ${groupId} is not an expandable playlist`);\n}","typeGuard":"const isExpandablePlaylist = (groupId: string): boolean => {\n  const g = groupStore.findGroupById(groupId);\n  const l = groupStore.findGroupLeader(groupId);\n  return !!g && !!l?.entries && !!g.entries;\n};","tryCatchPattern":"try {\n  await expandPlaylistGroup(groupId, selection);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('missing entry metadata')) {\n    toast.error('This item is not a valid playlist.');\n    return;\n  }\n  throw e;\n}","preventionTips":["Only route playlist groups into the expansion code path.","Assert leader.entries is present right after receiving the playlist payload from the backend.","Avoid deleting/replacing leader items between add and expansion."],"tags":["playlist","state-management","missing-metadata"],"backgroundTag":"missing-required-config-field","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"}