mckaywrigley/chatbot-ui · error · Error

error.message

Error message

error.message

What it means

getAssistantFilesByAssistantId selects a single row from a view/table keyed by assistant id and throws error.message when no data comes back. Because the code checks !assistantFiles rather than error, this throws even when the query legitimately returns zero rows — and in that case error is null, so error.message throws 'Cannot read properties of null' instead. It conflates 'not found' with 'query failed'.

Source

Thrown at db/assistant-files.ts:18

import { supabase } from "@/lib/supabase/browser-client"
import { TablesInsert } from "@/supabase/types"

export const getAssistantFilesByAssistantId = async (assistantId: string) => {
  const { data: assistantFiles, error } = await supabase
    .from("assistants")
    .select(
      `
        id, 
        name, 
        files (*)
      `
    )
    .eq("id", assistantId)
    .single()

  if (!assistantFiles) {
    throw new Error(error.message)
  }

  return assistantFiles
}

export const createAssistantFile = async (
  assistantFile: TablesInsert<"assistant_files">
) => {
  const { data: createdAssistantFile, error } = await supabase
    .from("assistant_files")
    .insert(assistantFile)
    .select("*")

  if (!createdAssistantFile) {
    throw new Error(error.message)
  }

  return createdAssistantFile

View on GitHub (pinned to 81328b61d2)

Solutions

  1. Distinguish the two cases: check error first, then treat null data as 'not found' and return null or throw a dedicated NotFoundError
  2. Verify the assistantId exists and the current user's RLS SELECT policy covers assistant_files
  3. Validate assistantId is a UUID before querying
  4. Re-run the query in the Supabase table editor to see whether the row is visible to your role

Example fix

// before
if (!assistantFiles) {
  throw new Error(error.message)
}

// after
if (error) throw new Error(`getAssistantFiles failed: ${error.message}`)
if (!assistantFiles) return null // or throw new NotFoundError(`No files for assistant ${assistantId}`)
Defensive patterns

Strategy: type-guard

Validate before calling

const isUuid = (id: string) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id)
if (!isUuid(assistantId)) throw new Error('invalid assistantId')

Type guard

const hasFiles = (x: unknown): x is { files: unknown[] } =>
  !!x && typeof x === 'object' && Array.isArray((x as any).files)

Try / catch

try { const files = await getAssistantFilesByAssistantId(id) } catch (e) { if (e instanceof TypeError) return [] /* not-found path */ throw e }

Prevention

When it happens

Trigger: Passing an assistantId that has no files row (error is null → TypeError reading 'message'); an RLS SELECT policy hiding the row from the current user; a malformed UUID for id causing a PostgREST 22P02 invalid-input error.

Common situations: Fetching an assistant created before the assistant_files row existed; RLS enabled without a SELECT policy; integration tests using random IDs; .single() on an empty result set.

Related errors


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