mckaywrigley/chatbot-ui · error

Error uploading image

Error message

Error uploading image

What it means

Thrown by uploadAssistantImage when supabase.storage.from("assistant_images").upload(filePath, image, { upsert: true }) returns an error. Supabase Storage returns errors such as 'Bucket not found', 'Duplicate' (when upsert can't overwrite), 'row-level security violation', or 'Payload too large' — all collapsed into this generic message. The file is never stored and the function aborts before returning the new path.

Source

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

  if (currentPath.length > 0) {
    const { error: deleteError } = await supabase.storage
      .from(bucket)
      .remove([currentPath])

    if (deleteError) {
      throw new Error("Error deleting old image")
    }
  }

  const { error } = await supabase.storage
    .from(bucket)
    .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. Log the underlying error object — its message ('Bucket not found', 'row-level security policy', 'Duplicate') identifies the exact cause.
  2. Create the 'assistant_images' bucket if missing and add INSERT + UPDATE (for upsert) policies scoped to auth.uid() = (storage.foldername(name))[1].
  3. Ensure the user is authenticated (valid Supabase session) before calling uploadAssistantImage — refresh the session if the JWT is stale.
  4. Verify NEXT_PUBLIC_SUPABASE_URL / ANON_KEY env vars point at the project that has the bucket.

Example fix

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

// after
if (error) {
  throw new Error(`Error uploading image: ${error.message}`)
}
Defensive patterns

Strategy: retry

Validate before calling

const { data: session } = await supabase.auth.getSession()
if (!session.session) {
  throw new Error("Sign in before uploading an assistant image")
}

Type guard

const isStorageError = (e: unknown): e is { message: string; statusCode?: string } =>
  typeof e === "object" && e !== null && "message" in e

Try / catch

let lastErr: unknown
for (let attempt = 0; attempt < 3; attempt++) {
  const { error } = await supabase.storage.from("assistant_images").upload(path, image, { upsert: true })
  if (!error) break
  lastErr = error
  if (!/network|fetch|timeout/i.test(error.message)) break // only retry transient errors
  await new Promise(r => setTimeout(r, 500 * 2 ** attempt))
}

Prevention

When it happens

Trigger: Uploading an image whose object key user_id/assistant_id/timestamp violates a storage INSERT/UPDATE policy; bucket 'assistant_images' doesn't exist in the project; session expired so the anon JWT fails the policy; image content-type rejected; or Supabase's global 50MB object cap hit (unlikely at the 6MB app limit).

Common situations: Missing or wrong storage.objects policies after creating the bucket via dashboard; using the anon key client-side while policies require owner; supabase URL/keys env vars misconfigured per environment; expired auth session in a long-lived browser tab.

Related errors


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