{"record":{"id":"1e5cc8c89cbec920","repo":"mckaywrigley/chatbot-ui","slug":"error-uploading-image","errorCode":null,"errorMessage":"Error uploading image","messagePattern":"Error uploading image","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db/storage/assistant-images.ts","lineNumber":36,"sourceCode":"\n  if (currentPath.length > 0) {\n    const { error: deleteError } = await supabase.storage\n      .from(bucket)\n      .remove([currentPath])\n\n    if (deleteError) {\n      throw new Error(\"Error deleting old image\")\n    }\n  }\n\n  const { error } = await supabase.storage\n    .from(bucket)\n    .upload(filePath, image, {\n      upsert: true\n    })\n\n  if (error) {\n    throw new Error(\"Error uploading image\")\n  }\n\n  return filePath\n}\n\nexport const getAssistantImageFromStorage = async (filePath: string) => {\n  try {\n    const { data, error } = await supabase.storage\n      .from(\"assistant_images\")\n      .createSignedUrl(filePath, 60 * 60 * 24) // 24hrs\n\n    if (error) {\n      throw new Error(\"Error downloading assistant image\")\n    }\n\n    return data.signedUrl\n  } catch (error) {\n    console.error(error)","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/mckaywrigley/chatbot-ui/blob/81328b61d2a4ab597a7a057be70e785cf756d9f8/db/storage/assistant-images.ts#L18-L54","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Log the underlying error object — its message ('Bucket not found', 'row-level security policy', 'Duplicate') identifies the exact cause.","Create the 'assistant_images' bucket if missing and add INSERT + UPDATE (for upsert) policies scoped to auth.uid() = (storage.foldername(name))[1].","Ensure the user is authenticated (valid Supabase session) before calling uploadAssistantImage — refresh the session if the JWT is stale.","Verify NEXT_PUBLIC_SUPABASE_URL / ANON_KEY env vars point at the project that has the bucket."],"exampleFix":"// before\nif (error) {\n  throw new Error(\"Error uploading image\")\n}\n\n// after\nif (error) {\n  throw new Error(`Error uploading image: ${error.message}`)\n}","handlingStrategy":"retry","validationCode":"const { data: session } = await supabase.auth.getSession()\nif (!session.session) {\n  throw new Error(\"Sign in before uploading an assistant image\")\n}","typeGuard":"const isStorageError = (e: unknown): e is { message: string; statusCode?: string } =>\n  typeof e === \"object\" && e !== null && \"message\" in e","tryCatchPattern":"let lastErr: unknown\nfor (let attempt = 0; attempt < 3; attempt++) {\n  const { error } = await supabase.storage.from(\"assistant_images\").upload(path, image, { upsert: true })\n  if (!error) break\n  lastErr = error\n  if (!/network|fetch|timeout/i.test(error.message)) break // only retry transient errors\n  await new Promise(r => setTimeout(r, 500 * 2 ** attempt))\n}","preventionTips":["Verify the bucket and INSERT/UPDATE policies exist before shipping each environment.","Refresh expired sessions before storage writes.","Preserve error.message when rethrowing so RLS vs bucket issues are diagnosable."],"tags":["supabase","storage","upload","rls","assistant-images"],"backgroundTag":"supabase-storage-upload-failed","analyzedSha":"81328b61d2a4ab597a7a057be70e785cf756d9f8","analyzedAt":"2026-08-27T19:24:42.689Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}