Skip to content

Fix for archived episodes re-added to UpNext#3876

Open
yaelirub wants to merge 1 commit intotrunkfrom
fix/archived_episodes_reappear
Open

Fix for archived episodes re-added to UpNext#3876
yaelirub wants to merge 1 commit intotrunkfrom
fix/archived_episodes_reappear

Conversation

@yaelirub
Copy link
Contributor

@yaelirub yaelirub commented Jan 17, 2026

Fixes PCIOS-203

The Problem

The issue occurs during Up Next synchronization between devices. Here's what's happening:

  1. Server has outdated Up Next data

From the logs:

  • One user has 369 episodes in their server-side Up Next queue and experienced 284 un-archiving incidents
  • Another user has 28-30 episodes and experienced 54 un-archiving incidents
  1. Sync doesn't check archived status

In /Modules/Server/Sources/PocketCastsServer/Public/Sync/UpNextSyncTask.swift:206-212, when incoming episodes from the server are not found in the local Up Next queue, the code never checks if localEpisode.archived == true before adding it back to Up Next.

  1. Episodes get un-archived

Later, in podcasts/DownloadManager.swift:476-487, when episodes are queued for download, the system detects they're archived and un-archives them.

  1. Apple Watch connection

The logs show WatchManager: Unknown message type: downloadRequest shortly before syncs. When users interact with their Watch, it triggers:

  • Background refreshes
  • Up Next syncs that pull the server's outdated queue (which still contains archived episodes)
  • Re-addition of archived episodes to the local queue

The Fix
The UpNextSyncTask should check if an episode is archived before re-adding it to the queue. At line 207 in UpNextSyncTask.swift, add an archived status check:

    // Skip archived episodes                                                                                                                                                                                                                             
    if let episode = localEpisode as? Episode, episode.archived {                                                                                                                                                                                         
        FileLog.shared.addMessage("UpNextSyncTask: Episode \(localEpisode.displayableTitle()) is archived, skipping")                                                                                                                                     
        continue                                                                                                                                                                                                                                          
    }                                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                          FileLog.shared.addMessage("UpNextSyncTask: Episode \(localEpisode.displayableTitle()) exists in local DB, adding to the queue")                                                                                                                       
    // ... rest of the code                                                                                                                                                                                                                               
}

To test

Not sure if we were ever able to reproduce this issue consistently. @Automattic/pocket-casts-ios , any idea how to test if this fix makes sense?

Checklist

  • I have considered if this change warrants user-facing release notes and have added them to CHANGELOG.md if necessary.
  • I have considered adding unit tests for my changes.
  • I have updated (or requested that someone edit) the spreadsheet to reflect any new or changed analytics.

…rchived episodes during Up Next synchronization
@yaelirub yaelirub requested a review from a team as a code owner January 17, 2026 02:05
@yaelirub yaelirub requested review from bjtitus and removed request for a team January 17, 2026 02:05
@yaelirub yaelirub added Up Next issues related to the Up Next feature Bug labels Jan 17, 2026
@yaelirub yaelirub added this to the 8.5 milestone Jan 19, 2026
@bjtitus
Copy link
Contributor

bjtitus commented Jan 20, 2026

Thanks! I think this would fix a lot of the reports but I think it introduces an issue where the local archived state could be stale. This is probably a lot less common that the normal Up Next → Archived state, though.

Before After
Before.mp4
After.mp4
  1. Add episodes from a podcast to Up Next
  2. Refresh from Profile
  3. ✅ Both queues should match
  4. Archive all of that podcast's episodes (it could just be a few but this makes it obvious), removing all of those episodes from Up Next
  5. Refresh from Profile
  6. ✅ Both queues should match with none from that podcast
  7. Unarchive that podcast's episodes on one device and add them back to Up Next
  8. Refresh on that device, which should push up the Up Next with unarchived added back
  9. Refresh the device where the episodes are still unarchived
  10. ❌ The Up Next Queue diverges on each device for me. I believe because this change drops them with a stale archived state. I do see the log:
UpNextSyncTask: Episode Ana Gasteyer is archived, skipping

It seems like given enough refreshes the queues do converge again, though, and those archived episodes are added back. Maybe this is better than older archived episodes coming back?

I wondered if this could be fixed by changing our sync ordering and running SyncTask before UpNextSyncTask but we do sometimes use only UpNextSyncTask.

@yaelirub yaelirub mentioned this pull request Jan 23, 2026
3 tasks
@yaelirub
Copy link
Contributor Author

@bjtitus , should this be closed given #3873 or could this still be a valid solution combined with your recommendations in the comment above?

@bjtitus
Copy link
Contributor

bjtitus commented Jan 24, 2026

@yaelirub I think we can close this if that's alright with you.

If we find we continue to get complaints or our quality project doesn't cover this, maybe we can introduce this with some safeguards like checking ServerSettings.lastSyncTime to see if archived was recently updated.

@bjtitus
Copy link
Contributor

bjtitus commented Jan 24, 2026

My suggestion if we want to keep this would be to Feature Flag it and also check that archived was refreshed:

if FeatureFlag.skipArchivedEpisodesInUpNextSync.enabled,
   let episode = localEpisode as? Episode,
   episode.archived,
   isArchiveDataFresh() {
	FileLog.shared.addMessage("UpNextSyncTask: Episode \(localEpisode.displayableTitle()) is archived, skipping")
	continue
}
private func isArchiveDataFresh() -> Bool {
	guard let lastSyncTime = ServerSettings.lastSyncTime else {
		FileLog.shared.addMessage("UpNextSyncTask: No last sync time, archive data not considered fresh")
		return false
	}

	let timeSinceLastSync = abs(lastSyncTime.timeIntervalSinceNow)
	let isFresh = timeSinceLastSync < Self.archiveFreshnessThreshold

	if !isFresh {
		FileLog.shared.addMessage("UpNextSyncTask: Archive data is stale (last sync \(Int(timeSinceLastSync))s ago), not skipping archived episodes")
	}

	return isFresh
}

archived-episodes-reappear.patch

@pocketcasts pocketcasts modified the milestones: 8.5, 8.6 Feb 2, 2026
@pocketcasts
Copy link
Contributor

Version 8.5 has now entered code-freeze, so the milestone of this PR has been updated to 8.6.

@pocketcasts pocketcasts modified the milestones: 8.6, 8.7 Feb 16, 2026
@pocketcasts
Copy link
Contributor

Version 8.6 has now entered code-freeze, so the milestone of this PR has been updated to 8.7.

@pocketcasts pocketcasts modified the milestones: 8.7, 8.8 Mar 2, 2026
@pocketcasts
Copy link
Contributor

Version 8.7 has now entered code-freeze, so the milestone of this PR has been updated to 8.8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug Up Next issues related to the Up Next feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants