mckaywrigley/chatbot-ui · error · Error

error.message

Error message

error.message

What it means

getAssistantToolsByAssistantId selects a single row of assistant tools by assistant id and throws error.message when no data returns. The !assistantTools check conflates a legitimate empty result with a query failure, so a missing row throws with a null-dereference message ('Cannot read properties of null (reading "message")') because error is null on empty results.

Source

Thrown at db/assistant-tools.ts:18

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

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

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

  return assistantTools
}

export const createAssistantTool = async (
  assistantTool: TablesInsert<"assistant_tools">
) => {
  const { data: createdAssistantTool, error } = await supabase
    .from("assistant_tools")
    .insert(assistantTool)
    .select("*")

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

  return createdAssistantTool

View on GitHub (pinned to 81328b61d2)

Solutions

  1. Check error before data and return null/throw NotFound for empty results
  2. Verify the row exists with a direct Supabase query as the same role
  3. Validate assistantId format before calling
  4. Ensure migrations creating the assistant_tools view ran in this environment

Example fix

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

// after
if (error) throw new Error(`getAssistantTools failed: ${error.message}`)
if (!assistantTools) return null
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

try { const t = await getAssistantToolsByAssistantId(id) } catch (e) { if (e instanceof TypeError) return [] throw e }

Prevention

When it happens

Trigger: Querying an assistantId with no assistant_tools row; RLS SELECT policy hiding the row; non-UUID assistantId causing PostgREST input syntax error; view dependency invalid.

Common situations: Assistants created without tool assignments; new environments where the view/table isn't migrated yet; tests with random UUIDs.

Related errors


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