{"record":{"id":"5098f4f23f0d4f79","repo":"mckaywrigley/chatbot-ui","slug":"error-message-5098f4","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"db/assistants.ts","lineNumber":12,"sourceCode":"import { supabase } from \"@/lib/supabase/browser-client\"\nimport { TablesInsert, TablesUpdate } from \"@/supabase/types\"\n\nexport const getAssistantById = async (assistantId: string) => {\n  const { data: assistant, error } = await supabase\n    .from(\"assistants\")\n    .select(\"*\")\n    .eq(\"id\", assistantId)\n    .single()\n\n  if (!assistant) {\n    throw new Error(error.message)\n  }\n\n  return assistant\n}\n\nexport const getAssistantWorkspacesByWorkspaceId = async (\n  workspaceId: string\n) => {\n  const { data: workspace, error } = await supabase\n    .from(\"workspaces\")\n    .select(\n      `\n      id,\n      name,\n      assistants (*)\n    `\n    )\n    .eq(\"id\", workspaceId)","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/mckaywrigley/chatbot-ui/blob/81328b61d2a4ab597a7a057be70e785cf756d9f8/db/assistants.ts#L1-L30","documentation":"getAssistantById selects a single assistants row by id and throws error.message when no data returns. Because the guard is on !assistant rather than error, a not-found id (where error is null) crashes with 'Cannot read properties of null' instead of a clean message, and genuine query errors (RLS, connection) surface their raw message.","triggerScenarios":"Looking up a deleted or never-existing assistantId; RLS SELECT policy hiding the row; invalid UUID string; Supabase project unreachable returning a fetch error.","commonSituations":"Stale assistant IDs in URLs after deletion; cross-workspace access blocked by RLS; deep links shared between users; test fixtures wiped between runs.","solutions":["Check error before data and model 'not found' explicitly (return null or throw a NotFound error)","Validate the id is a UUID before querying","Confirm the RLS SELECT policy allows the requesting user","Cache/verify existence at the API layer before dereferencing"],"exampleFix":"// before\nif (!assistant) {\n  throw new Error(error.message)\n}\n\n// after\nif (error) throw new Error(`getAssistantById failed: ${error.message}`)\nif (!assistant) throw new NotFoundError(`Assistant ${assistantId} not found`)\n// or: return null","handlingStrategy":"type-guard","validationCode":"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)\nif (!isUuid(assistantId)) return notFound()","typeGuard":"const isAssistant = (x: unknown): x is { id: string; user_id: string } =>\n  !!x && typeof x === 'object' && typeof (x as any).id === 'string'","tryCatchPattern":"try { const a = await getAssistantById(id); if (!a) return notFound() } catch (e) { if (e instanceof TypeError) return notFound(); throw e }","preventionTips":["Validate id format at the API boundary","Return 404 for missing assistants instead of 500","Patch the lib to check error before data"],"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"}