{"record":{"id":"30ad1558f5c8c7c3","repo":"Zackriya-Solutions/meetily","slug":"summary-contains-no-visible-content-to-save","errorCode":null,"errorMessage":"Summary contains no visible content to save.","messagePattern":"Summary contains no visible content to save\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/hooks/meeting-details/useMeetingData.ts","lineNumber":44,"sourceCode":"\n  // Sidebar context\n  const { setCurrentMeeting, setMeetings, meetings: sidebarMeetings } = useSidebar();\n\n  // Sync aiSummary state when summaryData prop changes (fixes display of fetched summaries)\n  useEffect(() => {\n    console.log('[useMeetingData] Syncing summary data from prop:', summaryData ? 'present' : 'null');\n    setAiSummary(summaryData);\n  }, [summaryData]); // Only trigger when parent prop changes, not when aiSummary changes\n\n  const handleSummaryChange = useCallback((newSummary: Summary) => {\n    setAiSummary(newSummary);\n  }, []);\n\n\n\n  const handleSaveSummary = useCallback(async (summary: MeetingSummary) => {\n    if (!hasVisibleSummaryContent(summary)) {\n      throw new Error('Summary contains no visible content to save.');\n    }\n\n    const formattedSummary = 'markdown' in summary || 'summary_json' in summary\n      ? summary\n      : { MeetingName: meetingTitle, ...summary };\n    await invokeTauri('api_save_meeting_summary', {\n      meetingId: meeting.id,\n      summary: formattedSummary,\n    });\n  }, [meeting.id, meetingTitle]);\n\n  const saveAllChanges = useCallback(async () => {\n    setIsSaving(true);\n    try {\n      // Save BlockNote editor changes if dirty\n      if (blockNoteSummaryRef.current?.isDirty) {\n        console.log('💾 Saving BlockNote editor changes...');\n        await blockNoteSummaryRef.current.saveSummary();","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/Zackriya-Solutions/meetily/blob/a2cb62e827da7ef59f65064c97233efb2313878e/frontend/src/hooks/meeting-details/useMeetingData.ts#L26-L62","documentation":"handleSaveSummary in useMeetingData throws this when the MeetingSummary object being saved has no visible content, i.e. hasVisibleSummaryContent(summary) returns false. The app refuses to persist a summary that would render as empty (no title, no tldr/body/sections of substance). It is a data-validation guard placed before the api_save_meeting_summary Tauri command is invoked.","triggerScenarios":"Calling handleSaveSummary(summary) from useMeetingData with a summary object whose visible fields (e.g. MeetingName, Tldr, and section/action item content) are all empty, null, or whitespace-only, so hasVisibleSummaryContent fails.","commonSituations":"A summarization run produced an empty result (model returned nothing or parsing stripped all content) and the UI still tried to save; user clicked Save before the summary finished generating; a migration or older meeting record yielded a summary with only internal/hidden fields.","solutions":["Check hasVisibleSummaryContent(summary) in the caller before invoking handleSaveSummary, and show a validation message instead of saving.","Verify the summarizer output actually populated visible fields (Tldr, sections, action items) before attempting save.","Regenerate the summary for the meeting, then save.","If the summary is legitimately minimal, populate at least a title/tldr so it passes the visibility check."],"exampleFix":"// before\nawait handleSaveSummary(summary);\n// after\nif (hasVisibleSummaryContent(summary)) {\n  await handleSaveSummary(summary);\n} else {\n  showToast('Nothing to save: the summary is empty.');\n}","handlingStrategy":"validation","validationCode":"import { hasVisibleSummaryContent } from '@/lib/summary';\n// in the component before saving:\nif (!hasVisibleSummaryContent(summary)) {\n  toast.error('Summary is empty; nothing to save.');\n  return;\n}\nawait handleSaveSummary(summary);","typeGuard":"function isSavableSummary(s: MeetingSummary): boolean {\n  return hasVisibleSummaryContent(s) && (typeof (s as any).Tldr === 'string' || 'summary_json' in s || 'markdown' in s);\n}","tryCatchPattern":"try {\n  await handleSaveSummary(summary);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('no visible content')) {\n    toast.error('Nothing to save: the summary is empty.');\n  } else { throw e; }\n}","preventionTips":["Disable the Save button until hasVisibleSummaryContent(summary) is true.","Check summarizer output completeness before entering edit/save flow.","Render an explicit 'empty summary' state so users never try to save blank content."],"tags":["react","validation","empty-content","tauri"],"backgroundTag":"empty-required-field","analyzedSha":"a2cb62e827da7ef59f65064c97233efb2313878e","analyzedAt":"2026-09-12T11:12:14.152Z","contentChangedAt":"2026-09-12T11:12:14.152Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}