From dfda2da827f9dd750ec347ae82604c3c2f8755ce Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Sun, 8 Mar 2026 19:29:18 -0400 Subject: [PATCH] Fix updateTag errors when called from cron jobs and detached promises updateTag (Next.js cache revalidation) only works inside Route Handlers and Server Actions. It was being called from cron jobs and fire-and-forget promises, causing intermittent errors attributed to whichever route was rendering concurrently (e.g. /explore). - Pass `{ revalidate: false }` from cron and fire-and-forget contexts - Add try-catch around updateTag calls as a safety net Co-Authored-By: Claude Opus 4.6 --- lib/cron.ts | 2 +- lib/services/credits.ts | 7 ++++++- lib/services/metadata.ts | 15 ++++++++++----- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/cron.ts b/lib/cron.ts index e6e7e78..ac2a5b7 100644 --- a/lib/cron.ts +++ b/lib/cron.ts @@ -301,7 +301,7 @@ async function refreshCreditsJob() { (castEntry.lastFetchedAt && castEntry.lastFetchedAt < stale); if (needsRefresh) { - await refreshCredits(titleId); + await refreshCredits(titleId, { revalidate: false }); await Bun.sleep(RATE_LIMIT_MS); } } diff --git a/lib/services/credits.ts b/lib/services/credits.ts index 8d1914d..75cc092 100644 --- a/lib/services/credits.ts +++ b/lib/services/credits.ts @@ -280,7 +280,12 @@ export async function refreshCredits( if (revalidate) { for (const personId of personIds.values()) { - updateTag(`person-${personId}`); + try { + updateTag(`person-${personId}`); + } catch { + // updateTag only works inside Route Handlers / Server Actions; + // swallow the error when called from cron jobs or detached promises. + } } } diff --git a/lib/services/metadata.ts b/lib/services/metadata.ts index ebcc3ee..ef97724 100644 --- a/lib/services/metadata.ts +++ b/lib/services/metadata.ts @@ -173,7 +173,7 @@ async function _getOrFetchTitleByTmdbId(tmdbId: number, type: "movie" | "tv") { extractAndStoreColors(existing.id, show.poster_path ?? null).catch( (err) => log.debug("Color extraction failed:", err), ); - refreshCredits(existing.id).catch((err) => + refreshCredits(existing.id, { revalidate: false }).catch((err) => log.debug("Credits enrichment failed:", err), ); refreshTrailer(existing.id).catch((err) => @@ -227,7 +227,7 @@ async function _getOrFetchTitleByTmdbId(tmdbId: number, type: "movie" | "tv") { extractAndStoreColors(row.id, movie.poster_path ?? null).catch((err) => log.debug("Color extraction failed:", err), ); - refreshCredits(row.id).catch((err) => + refreshCredits(row.id, { revalidate: false }).catch((err) => log.debug("Credits enrichment failed:", err), ); refreshTrailer(row.id).catch((err) => @@ -276,7 +276,7 @@ async function _getOrFetchTitleByTmdbId(tmdbId: number, type: "movie" | "tv") { extractAndStoreColors(row.id, show.poster_path ?? null).catch((err) => log.debug("Color extraction failed:", err), ); - refreshCredits(row.id).catch((err) => + refreshCredits(row.id, { revalidate: false }).catch((err) => log.debug("Credits enrichment failed:", err), ); refreshTrailer(row.id).catch((err) => @@ -352,7 +352,7 @@ export async function refreshTitle(titleId: string) { refreshTrailer(updated.id).catch((err) => log.debug("Trailer enrichment failed:", err), ); - refreshCredits(updated.id).catch((err) => + refreshCredits(updated.id, { revalidate: false }).catch((err) => log.debug("Credits enrichment failed:", err), ); if (imageCacheEnabled()) { @@ -586,7 +586,12 @@ export async function refreshRecommendations( }); if (revalidate) { - updateTag(`recs-${titleId}`); + try { + updateTag(`recs-${titleId}`); + } catch { + // updateTag only works inside Route Handlers / Server Actions; + // swallow when called from cron jobs or detached promises. + } } }