mckaywrigley/chatbot-ui · error
Error downloading file
Error message
Error downloading file
What it means
Thrown by getFileFromStorage when createSignedUrl(filePath, 86400) on the 'files' bucket returns an error. Signed URL generation fails when the object doesn't exist at that path or the caller lacks SELECT access. The function does log the underlying error with the path before throwing, so server/console output shows the real StorageError.
Source
Thrown at db/storage/files.ts:53
}
export const deleteFileFromStorage = async (filePath: string) => {
const { error } = await supabase.storage.from("files").remove([filePath])
if (error) {
toast.error("Failed to remove file!")
return
}
}
export const getFileFromStorage = async (filePath: string) => {
const { data, error } = await supabase.storage
.from("files")
.createSignedUrl(filePath, 60 * 60 * 24) // 24hrs
if (error) {
console.error(`Error uploading file with path: ${filePath}`, error)
throw new Error("Error downloading file")
}
return data.signedUrl
}
View on GitHub (pinned to 81328b61d2)
Solutions
- Read the console error logged just before the throw — it includes filePath and the StorageError message.
- Verify the object exists at that path in the Supabase dashboard (Storage > files).
- Add a storage.objects SELECT policy on 'files' for authenticated users/owners.
- If objects can be deleted out-of-band, degrade gracefully (fallback placeholder) instead of throwing.
Example fix
// before
if (error) {
console.error(`Error uploading file with path: ${filePath}`, error)
throw new Error("Error downloading file")
}
// after
if (error) {
console.error(`Error signing URL for path: ${filePath}`, error)
return null // let the caller show a fallback
} Defensive patterns
Strategy: fallback
Validate before calling
const { data } = await supabase.storage.from("files").list(folder(path))
if (!data?.some(o => o.name === name(path))) return placeholderUrl Type guard
const hasSignedUrl = (r: unknown): r is { signedUrl: string } =>
!!r && typeof (r as { signedUrl?: string }).signedUrl === "string" Try / catch
try {
url = await getFileFromStorage(path)
} catch {
url = null // show 'file unavailable' in UI instead of crashing the message list
} Prevention
- Fall back to a placeholder for deleted attachments rather than throwing mid-render.
- Keep DB rows and storage objects lifecycle in sync: delete rows when objects are purged (or vice versa).
- Maintain SELECT storage policies on the files bucket.
When it happens
Trigger: Requesting a signed URL for a path that was deleted (deleteFileFromStorage ran first), a stale base64(file_id) path after a record was recreated, a path from a different environment's bucket, or a private 'files' bucket with no SELECT policy for the requesting role.
Common situations: Chat history referencing attachments whose storage objects were removed; multi-environment DBs sharing rows but not buckets; missing storage.objects SELECT policy; expired session when policies require authenticated users.
Related errors
- Error downloading assistant image
- Error uploading file
- Error downloading message image
- Error deleting old image
- Error uploading image
AI-assisted analysis of mckaywrigley/chatbot-ui@81328b61d2 (2026-08-27).
Data as JSON: /api/errors/57701211d84dbd4f.
Report an issue: GitHub.