From 843a2ce727d8d0d4ea267db6a6033d5f4cf19f5c Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Fri, 27 Mar 2026 01:36:23 +0100 Subject: [PATCH] fix(federation): store absolute URLs for replicated user avatars Bare filenames stored on replicated user stubs can't be resolved by the home WS (normalizeUserAssets only runs for remote origins). Now resolves avatar/banner to absolute URLs pointing to the user's home instance so they render correctly without page refresh. Also overwrites stale bare filenames from the prior deploy. --- packages/server/src/routes/federation.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/server/src/routes/federation.ts b/packages/server/src/routes/federation.ts index a5a7031f..05ebbe08 100644 --- a/packages/server/src/routes/federation.ts +++ b/packages/server/src/routes/federation.ts @@ -1872,11 +1872,21 @@ function hydrateReplicatedUserProfile( if (!profile) return user; if (!user.homeInstance) return user; // Don't update native users + // Resolve bare filenames to absolute URLs pointing to the home instance. + // The home WS doesn't run normalizeUserAssets on replicated users' avatars, + // so they must be stored as absolute URLs to render correctly. + const resolveUrl = (filename: string | null | undefined): string | null => { + if (!filename) return null; + if (filename.startsWith('http')) return filename; + return `${user.homeInstance}/api/uploads/${filename}`; + }; + const updates: Record = {}; if (profile.displayName && !user.displayName) updates.displayName = profile.displayName; - if (profile.avatar && !user.avatar) updates.avatar = profile.avatar; + // Overwrite avatar/banner if missing OR if it's a stale bare filename (not an absolute URL) + if (profile.avatar && (!user.avatar || !user.avatar.startsWith('http'))) updates.avatar = resolveUrl(profile.avatar); if (profile.avatarColor && !user.avatarColor) updates.avatarColor = profile.avatarColor; - if (profile.banner && !user.banner) updates.banner = profile.banner; + if (profile.banner && (!user.banner || !user.banner.startsWith('http'))) updates.banner = resolveUrl(profile.banner); if (profile.bio && !user.bio) updates.bio = profile.bio; if (Object.keys(updates).length === 0) return user;