{"record":{"id":"ff9eae40bdae5fee","repo":"mckaywrigley/chatbot-ui","slug":"error-message-ff9eae","errorCode":null,"errorMessage":"error.message","messagePattern":"error\\.message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"db/chat-files.ts","lineNumber":18,"sourceCode":"import { supabase } from \"@/lib/supabase/browser-client\"\nimport { TablesInsert } from \"@/supabase/types\"\n\nexport const getChatFilesByChatId = async (chatId: string) => {\n  const { data: chatFiles, error } = await supabase\n    .from(\"chats\")\n    .select(\n      `\n      id, \n      name, \n      files (*)\n    `\n    )\n    .eq(\"id\", chatId)\n    .single()\n\n  if (!chatFiles) {\n    throw new Error(error.message)\n  }\n\n  return chatFiles\n}\n\nexport const createChatFile = async (chatFile: TablesInsert<\"chat_files\">) => {\n  const { data: createdChatFile, error } = await supabase\n    .from(\"chat_files\")\n    .insert(chatFile)\n    .select(\"*\")\n\n  if (!createdChatFile) {\n    throw new Error(error.message)\n  }\n\n  return createdChatFile\n}\n","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/mckaywrigley/chatbot-ui/blob/81328b61d2a4ab597a7a057be70e785cf756d9f8/db/chat-files.ts#L1-L36","documentation":"getChatFilesByChatId selects a single row of chat files by chat id and throws error.message when no data returns. The !chatFiles guard treats an empty result as an error, but on empty results error is null, so the actual exception is 'Cannot read properties of null (reading message)' — masking the true not-found condition.","triggerScenarios":"Chat id with no chat_files row (new chat, no uploads yet); RLS SELECT policy hiding the row; invalid chat id; relation missing after schema drift.","commonSituations":"Opening a chat before any file is attached; member role without SELECT policy coverage; environment missing the chat_files view/table.","solutions":["Check error before data; return null or an empty structure when the chat simply has no files","Verify the chat exists and the caller can read chat_files under RLS","Validate the chatId format before querying","Ensure the chat_files table/view is migrated in this environment"],"exampleFix":"// before\nif (!chatFiles) {\n  throw new Error(error.message)\n}\n\n// after\nif (error) throw new Error(`getChatFilesByChatId failed: ${error.message}`)\nif (!chatFiles) return { chatId, files: [] } // or null","handlingStrategy":"type-guard","validationCode":"const isUuid = (id: string) => /^[0-9a-f-]{36}$/i.test(id)\nif (!isUuid(chatId)) return { files: [] }","typeGuard":"const hasFiles = (x: unknown): x is { files: unknown[] } =>\n  !!x && typeof x === 'object' && Array.isArray((x as any).files)","tryCatchPattern":"try { const r = await getChatFilesByChatId(chatId); if (!r) return [] } catch (e) { if (e instanceof TypeError) return []; throw e }","preventionTips":["Treat no-files as empty, not an error","Ensure chat exists before fetching files","Patch 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"}