mckaywrigley/chatbot-ui · error

Error downloading assistant image

Error message

Error downloading assistant image

What it means

Thrown by getAssistantImageFromStorage when createSignedUrl(filePath, 86400) on the assistant_images bucket returns an error. Signed-url creation fails server-side when the object at filePath doesn't exist or the caller can't SELECT it. Note the surrounding try/catch swallows the error and returns undefined, so callers see a missing URL rather than the throw.

Source

Thrown at db/storage/assistant-images.ts:49

    .upload(filePath, image, {
      upsert: true
    })

  if (error) {
    throw new Error("Error uploading image")
  }

  return filePath
}

export const getAssistantImageFromStorage = async (filePath: string) => {
  try {
    const { data, error } = await supabase.storage
      .from("assistant_images")
      .createSignedUrl(filePath, 60 * 60 * 24) // 24hrs

    if (error) {
      throw new Error("Error downloading assistant image")
    }

    return data.signedUrl
  } catch (error) {
    console.error(error)
  }
}

View on GitHub (pinned to 81328b61d2)

Solutions

  1. Check the console output first — the catch logs the real StorageError with its message ('Object not found' vs 'row-level security').
  2. Confirm assistant.image_path actually exists in the bucket via the Supabase dashboard storage browser.
  3. Add a storage.objects SELECT policy on assistant_images for authenticated users (or the object owner) so signed URLs can be issued.
  4. Re-throw or return null explicitly from the catch so callers can distinguish 'no image' from 'fetch failed'.

Example fix

// before
} catch (error) {
  console.error(error)
}

// after
} catch (error) {
  console.error(`Failed to sign URL for ${filePath}:`, error)
  return null
}
Defensive patterns

Strategy: fallback

Validate before calling

if (!filePath || filePath.length === 0) {
  // nothing to sign; skip the call
}

Type guard

const isSignedUrlResult = (
  r: unknown
): r is { signedUrl: string } =>
  typeof r === "object" && r !== null && typeof (r as any).signedUrl === "string"

Try / catch

let url: string | null = null
try {
  url = await getAssistantImageFromStorage(path)
} catch (e) {
  console.error("signed url failed", e)
  url = null // caller renders initials/placeholder
}

Prevention

When it happens

Trigger: Calling getAssistantImageFromStorage with a path that was deleted (e.g. after re-upload created a new timestamped path), an empty-string path, a path from another project/environment, or when no storage.objects SELECT policy covers the object for the current role.

Common situations: Rendering an avatar with a stale assistant.image_path saved in the DB; environments (local vs prod) pointing at different buckets; private bucket with no SELECT policy for authenticated users; the swallow-catch making debugging hard because only console.error fires.

Related errors


AI-assisted analysis of mckaywrigley/chatbot-ui@81328b61d2 (2026-08-27). Data as JSON: /api/errors/97991fbac6c26fda. Report an issue: GitHub.