mckaywrigley/chatbot-ui · error

Error deleting old image

Error message

Error deleting old image

What it means

Thrown by uploadAssistantImage when supabase.storage.from("assistant_images").remove([currentPath]) returns an error while trying to delete the assistant's previous image before uploading a new one. The underlying StorageError is discarded and replaced with this generic message. It almost always means the stored assistant.image_path no longer exists in the bucket, or the current user lacks DELETE permission on that object.

Source

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

) => {
  const bucket = "assistant_images"

  const imageSizeLimit = 6000000 // 6MB

  if (image.size > imageSizeLimit) {
    throw new Error(`Image must be less than ${imageSizeLimit / 1000000}MB`)
  }

  const currentPath = assistant.image_path
  let filePath = `${assistant.user_id}/${assistant.id}/${Date.now()}`

  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 {

View on GitHub (pinned to 81328b61d2)

Solutions

  1. Inspect the real cause by logging deleteError (and deleteError.message) before throwing — 'Object not found' vs 'row-level security' point to different fixes.
  2. If the error is 'not found', treat deletion of a non-existent old image as non-fatal: proceed with the upload instead of throwing.
  3. Add/adjust a storage.objects DELETE policy on assistant_images for the bucket owner (auth.uid() = (storage.foldername(name))[1]).
  4. Verify the bucket 'assistant_images' exists in the target Supabase project and the client uses the correct project URL/keys.

Example fix

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

// after
if (deleteError && !deleteError.message.includes("not found")) {
  console.error("Failed to delete old image:", deleteError)
  throw new Error(`Error deleting old image: ${deleteError.message}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before uploading, optionally confirm the old object exists
const { data: list } = await supabase.storage
  .from("assistant_images")
  .list(dirname(currentPath), { search: basename(currentPath) })
if (!list?.some(o => o.name === basename(currentPath))) {
  // old image already gone; skip delete
}

Type guard

const hasOldImage = (a: { image_path: string | null }): boolean =>
  typeof a.image_path === "string" && a.image_path.length > 0

Try / catch

try {
  await uploadAssistantImage(assistant, image)
} catch (e) {
  if (e instanceof Error && e.message === "Error deleting old image") {
    // old image missing/locked: retry upload skipping delete, or surface a toast
    toast.error("Could not replace the old image. Please retry.")
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: Calling uploadAssistantImage with an assistant whose image_path is set: the remove() call fails when (a) the object at image_path was already deleted or never committed, (b) the bucket 'assistant_images' is missing or misnamed, (c) the user's JWT doesn't satisfy a storage.objects DELETE policy for that path, or (d) the path was written by a different user_id prefix.

Common situations: Stale image_path in the assistants row after a manual bucket wipe or project migration; RLS storage policies that allow insert/update but not delete; switching between service-role and anon-key clients so the object owner differs; local dev pointing at a different Supabase project where the old object doesn't exist.

Related errors


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