mckaywrigley/chatbot-ui · error
Error downloading message image
Error message
Error downloading message image
What it means
Thrown by getMessageImageFromStorage when createSignedUrl(filePath, 86400) on the 'message_images' bucket returns an error. Supabase fails signed-url creation when the object doesn't exist at filePath or the caller's role can't SELECT it. Unlike getAssistantImageFromStorage, this version throws to the caller rather than swallowing the error.
Source
Thrown at db/storage/message-images.ts:29
const { error } = await supabase.storage.from(bucket).upload(path, image, {
upsert: true
})
if (error) {
throw new Error("Error uploading image")
}
return path
}
export const getMessageImageFromStorage = async (filePath: string) => {
const { data, error } = await supabase.storage
.from("message_images")
.createSignedUrl(filePath, 60 * 60 * 24) // 24hrs
if (error) {
throw new Error("Error downloading message image")
}
return data.signedUrl
}
View on GitHub (pinned to 81328b61d2)
Solutions
- Verify the object exists at the logged path in the Supabase storage dashboard.
- Add a storage.objects SELECT policy on message_images for authenticated users (or make the bucket public if appropriate).
- Wrap the call and fall back to a placeholder image when signing fails, so one bad message doesn't break the whole chat render.
- Audit for code paths that delete message images while messages still reference them.
Example fix
// before
const url = await getMessageImageFromStorage(path)
// after
let url: string | null = null
try {
url = await getMessageImageFromStorage(path)
} catch {
url = null // render placeholder
} Defensive patterns
Strategy: fallback
Validate before calling
if (!filePath) return placeholderUrl
Type guard
const isSignablePath = (p: unknown): p is string =>
typeof p === "string" && p.length > 0 && !p.startsWith("/") Try / catch
let url: string | null = null
try {
url = await getMessageImageFromStorage(path)
} catch {
url = null // render image placeholder in the chat bubble
} Prevention
- Never render message history without guarding signed-url failures — one missing object shouldn't break the thread.
- Keep SELECT policies on message_images aligned with who may view messages.
- Re-sign URLs on demand; never cache them beyond their 24h validity.
When it happens
Trigger: Loading a chat message whose image path was deleted from storage, was written to a different bucket/project, or isn't covered by a storage.objects SELECT policy for the current (possibly anon) role; passing an empty or malformed path string.
Common situations: Old messages referencing purged objects (retention jobs, manual bucket cleanup); private bucket without SELECT policies; rendering history while logged out where anon role can't read; environment mismatch between DB rows and storage bucket contents.
Related errors
- Error downloading assistant image
- Error downloading file
- Error uploading image
- Error deleting old image
- Error uploading image
AI-assisted analysis of mckaywrigley/chatbot-ui@81328b61d2 (2026-08-27).
Data as JSON: /api/errors/9942000d803b4887.
Report an issue: GitHub.