mckaywrigley/chatbot-ui · warning

File must be less than ${Math.floor(SIZE_LIMIT / 1000000)}MB

Error message

File must be less than ${Math.floor(SIZE_LIMIT / 1000000)}MB

What it means

Thrown by uploadFile when the File's byte size exceeds NEXT_PUBLIC_USER_FILE_SIZE_LIMIT (parsed as an integer, defaulting to 10000000 bytes = 10MB). This is a purely client-side guard executed before any network call to Supabase Storage. The template interpolates Math.floor(SIZE_LIMIT / 1000000) so the message shows the limit in whole MB.

Source

Thrown at db/storage/files.ts:17

import { supabase } from "@/lib/supabase/browser-client"
import { toast } from "sonner"

export const uploadFile = async (
  file: File,
  payload: {
    name: string
    user_id: string
    file_id: string
  }
) => {
  const SIZE_LIMIT = parseInt(
    process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "10000000"
  )

  if (file.size > SIZE_LIMIT) {
    throw new Error(
      `File must be less than ${Math.floor(SIZE_LIMIT / 1000000)}MB`
    )
  }

  const filePath = `${payload.user_id}/${Buffer.from(payload.file_id).toString("base64")}`

  const { error } = await supabase.storage
    .from("files")
    .upload(filePath, file, {
      upsert: true
    })

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

  return filePath
}

View on GitHub (pinned to 81328b61d2)

Solutions

  1. Compress or split the file, or raise NEXT_PUBLIC_USER_FILE_SIZE_LIMIT to an explicit byte value (e.g. '50000000') and rebuild the app.
  2. Verify the env var is a plain byte count with no unit suffix — '10mb' parseInts to 10 and breaks the check.
  3. Warn users in the UI before upload by checking file.size against the same limit client-side.
  4. Keep the Supabase Storage bucket's own size cap in sync if you raise this limit.

Example fix

// before
const SIZE_LIMIT = parseInt(
  process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "10000000"
)

// after
const SIZE_LIMIT = Number(
  process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "10000000"
)
if (!Number.isFinite(SIZE_LIMIT) || SIZE_LIMIT <= 0) {
  throw new Error("Invalid NEXT_PUBLIC_USER_FILE_SIZE_LIMIT")
}
Defensive patterns

Strategy: validation

Validate before calling

const SIZE_LIMIT = Number(process.env.NEXT_PUBLIC_USER_FILE_SIZE_LIMIT || "10000000")
if (file.size > SIZE_LIMIT) {
  toast.error(`File too large — max ${Math.floor(SIZE_LIMIT / 1_000_000)}MB`)
  // stop before calling uploadFile
}

Type guard

const isWithinLimit = (f: File, limit: number): boolean =>
  f.size <= limit && Number.isFinite(limit)

Try / catch

try {
  await uploadFile(file, payload)
} catch (e) {
  if (e instanceof Error && e.message.startsWith("File must be less than")) {
    toast.error(e.message) // user-fixable; no retry needed
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: Passing a file with file.size > SIZE_LIMIT — e.g. an 11MB PDF against the 10MB default; or setting NEXT_PUBLIC_USER_FILE_SIZE_LIMIT to a small value like '1000000' so previously fine files now throw. Because parseInt stops at the first non-digit, a malformed value like '10mb' parses as 10 (bytes), rejecting nearly everything.

Common situations: Env var set as '10MB' or '10 mb' instead of raw bytes; changing the limit per environment but only rebuilding one; large exports/recordings users try to attach; forgetting that NEXT_PUBLIC_ vars are inlined at build time so runtime .env changes have no effect until rebuild.

Related errors


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