{"record":{"id":"395c285218c02d72","repo":"mckaywrigley/chatbot-ui","slug":"error-message-395c28","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"db/assistant-tools.ts","lineNumber":18,"sourceCode":"import { supabase } from \"@/lib/supabase/browser-client\"\nimport { TablesInsert } from \"@/supabase/types\"\n\nexport const getAssistantToolsByAssistantId = async (assistantId: string) => {\n  const { data: assistantTools, error } = await supabase\n    .from(\"assistants\")\n    .select(\n      `\n        id, \n        name, \n        tools (*)\n      `\n    )\n    .eq(\"id\", assistantId)\n    .single()\n\n  if (!assistantTools) {\n    throw new Error(error.message)\n  }\n\n  return assistantTools\n}\n\nexport const createAssistantTool = async (\n  assistantTool: TablesInsert<\"assistant_tools\">\n) => {\n  const { data: createdAssistantTool, error } = await supabase\n    .from(\"assistant_tools\")\n    .insert(assistantTool)\n    .select(\"*\")\n\n  if (!createdAssistantTool) {\n    throw new Error(error.message)\n  }\n\n  return createdAssistantTool","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/mckaywrigley/chatbot-ui/blob/81328b61d2a4ab597a7a057be70e785cf756d9f8/db/assistant-tools.ts#L1-L36","documentation":"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.","triggerScenarios":"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.","commonSituations":"Assistants created without tool assignments; new environments where the view/table isn't migrated yet; tests with random UUIDs.","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"],"exampleFix":"// before\nif (!assistantTools) {\n  throw new Error(error.message)\n}\n\n// after\nif (error) throw new Error(`getAssistantTools failed: ${error.message}`)\nif (!assistantTools) return null","handlingStrategy":"type-guard","validationCode":"const isUuid = (id: string) => /^[0-9a-f-]{36}$/i.test(id)\nif (!isUuid(assistantId)) throw new Error('invalid assistantId')","typeGuard":"const hasTools = (x: unknown): x is { tools: unknown[] } =>\n  !!x && typeof x === 'object' && Array.isArray((x as any).tools)","tryCatchPattern":"try { const t = await getAssistantToolsByAssistantId(id) } catch (e) { if (e instanceof TypeError) return [] throw e }","preventionTips":["Default to empty tool list when none exist","Check error before data in wrappers","Keep view/table migrations in sync across environments"],"tags":["supabase","postgrest","not-found","single-row","null-deref"],"backgroundTag":"supabase-single-row-not-found","analyzedSha":"81328b61d2a4ab597a7a057be70e785cf756d9f8","analyzedAt":"2026-08-27T19:24:42.689Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}