{"record":{"id":"69951f140d9bce3d","repo":"mckaywrigley/chatbot-ui","slug":"image-must-be-less-than-imagesizelimit-1000000-69951f","errorCode":null,"errorMessage":"Image must be less than ${imageSizeLimit / 1000000}MB","messagePattern":"Image must be less than (.+?)MB","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"db/storage/profile-images.ts","lineNumber":13,"sourceCode":"import { supabase } from \"@/lib/supabase/browser-client\"\nimport { Tables } from \"@/supabase/types\"\n\nexport const uploadProfileImage = async (\n  profile: Tables<\"profiles\">,\n  image: File\n) => {\n  const bucket = \"profile_images\"\n\n  const imageSizeLimit = 2000000 // 2MB\n\n  if (image.size > imageSizeLimit) {\n    throw new Error(`Image must be less than ${imageSizeLimit / 1000000}MB`)\n  }\n\n  const currentPath = profile.image_path\n  let filePath = `${profile.user_id}/${Date.now()}`\n\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, {","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/mckaywrigley/chatbot-ui/blob/81328b61d2a4ab597a7a057be70e785cf756d9f8/db/storage/profile-images.ts#L1-L31","documentation":"Thrown by uploadProfileImage when the image File exceeds the hardcoded 2000000-byte (2MB) limit — the strictest of this app's three image limits (profile 2MB, assistant/message 6MB). It's a client-side check before any Supabase Storage call, so it fires synchronously with no network round-trip. The literal is defined in db/storage/profile-images.ts and is not env-configurable.","triggerScenarios":"Uploading a profile photo with image.size > 2000000: typical phone camera photos (3-15MB), PNG exports, or un-compressed canvas blobs. Any File object over 2MB triggers it immediately on submission.","commonSituations":"Users uploading full-resolution phone portraits; avatars cropped client-side but exported as lossless PNG at high resolution; developers confused because the same photo works for assistant images (6MB) but fails here; UI not pre-validating so the throw appears as a generic error toast.","solutions":["Resize/compress the avatar client-side before upload — profile images render small, so re-encode to ~512px JPEG/WebP at 80% quality, which lands well under 2MB.","Pre-check image.size in the picker UI and warn the user before submission.","If 2MB is too strict for your users, raise the constant in db/storage/profile-images.ts.","Accept HEIC but convert to JPEG client-side, since iPhone originals frequently exceed the cap."],"exampleFix":"// before\nconst result = await uploadProfileImage(profile, rawFile) // 4MB photo -> throws\n\n// after\nconst compressed = await resizeImage(rawFile, { maxDim: 512, quality: 0.8 })\nconst result = await uploadProfileImage(profile, compressed)","handlingStrategy":"validation","validationCode":"const MAX = 2_000_000\nif (image.size > MAX) {\n  image = await resizeImage(image, { maxDim: 512, quality: 0.8 })\n}\nif (image.size > MAX) {\n  toast.error(\"Profile image must be under 2MB\")\n  return\n}","typeGuard":"const isValidProfileImage = (f: File): boolean =>\n  f.type.startsWith(\"image/\") && f.size <= 2_000_000","tryCatchPattern":"try {\n  const { path, url } = await uploadProfileImage(profile, image)\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"less than 2MB\")) {\n    toast.error(\"Please choose a smaller image (under 2MB).\")\n  } else { throw e }\n}","preventionTips":["Auto-resize avatars client-side to ~512px before upload — small renders make 2MB generous.","Pre-check size in the picker so users get feedback before submitting.","Remember profile images have the strictest limit (2MB) vs assistant/message (6MB)."],"tags":["image","file-size","validation","profile-images"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"81328b61d2a4ab597a7a057be70e785cf756d9f8","analyzedAt":"2026-08-27T19:24:42.689Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}