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 createdAssistantToolView on GitHub (pinned to 81328b61d2)
Solutions
- Check error before data and return null/throw NotFound for empty results
- Verify the row exists with a direct Supabase query as the same role
- Validate assistantId format before calling
- 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
- Default to empty tool list when none exist
- Check error before data in wrappers
- Keep view/table migrations in sync across environments
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.