diff --git a/src/components/measurement-reminders/__tests__/vorsorge-dashboard-card-error-state.test.tsx b/src/components/measurement-reminders/__tests__/vorsorge-dashboard-card-error-state.test.tsx
new file mode 100644
index 000000000..1caf6002e
--- /dev/null
+++ b/src/components/measurement-reminders/__tests__/vorsorge-dashboard-card-error-state.test.tsx
@@ -0,0 +1,57 @@
+/**
+ * A reminder-read failure on the dashboard Vorsorge tile must not read as "no
+ * upcoming checkup reminders" โ a missed preventive-care nudge is the harm
+ * behind that fall-through. `useMeasurementReminders` is forced into its error
+ * state; the tile has to render a `query-error-row` with retry and never the
+ * empty copy.
+ *
+ * SSR-static render; the query-backed hooks are mocked so the error branch is
+ * synchronous.
+ */
+import { describe, expect, it, vi } from "vitest";
+import { renderToStaticMarkup } from "react-dom/server";
+
+vi.mock("@/hooks/use-measurement-reminders", () => ({
+ useMeasurementReminders: () => ({
+ data: undefined,
+ isError: true,
+ refetch: vi.fn(),
+ }),
+ useMeasurementReminderMutations: () => ({
+ satisfy: { mutate: vi.fn(), isPending: false },
+ }),
+}));
+
+vi.mock("@/hooks/use-encounters", () => ({
+ useEncounters: () => ({ data: { upcoming: [] } }),
+}));
+
+vi.mock("@/hooks/use-record-capabilities", () => ({
+ useRecordCapabilities: () => ({ canManage: true, canAdd: true }),
+}));
+
+vi.mock("next/navigation", () => ({
+ useRouter: () => ({ push: vi.fn(), replace: vi.fn() }),
+ usePathname: () => "/",
+ useSearchParams: () => new URLSearchParams(),
+}));
+
+import { I18nProvider } from "@/lib/i18n/context";
+import { VorsorgeDashboardCard } from "../vorsorge-dashboard-card";
+
+function render() {
+ return renderToStaticMarkup(
+
+
+ ,
+ );
+}
+
+describe(" โ a read failure is honest, not empty", () => {
+ it("renders the query-error row with retry and never the empty copy", () => {
+ const html = render();
+ expect(html).toContain('data-slot="query-error-row"');
+ expect(html).toContain('data-slot="query-error-row-retry"');
+ expect(html).not.toContain("No upcoming checkup reminders");
+ });
+});
diff --git a/src/components/measurement-reminders/vorsorge-dashboard-card.tsx b/src/components/measurement-reminders/vorsorge-dashboard-card.tsx
index 5f65c474e..848e5e996 100644
--- a/src/components/measurement-reminders/vorsorge-dashboard-card.tsx
+++ b/src/components/measurement-reminders/vorsorge-dashboard-card.tsx
@@ -32,6 +32,7 @@ import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { ListRow } from "@/components/ui/list-row";
+import { QueryErrorRow } from "@/components/ui/query-error-row";
import { ResponsiveSheet } from "@/components/ui/responsive-sheet";
import { Skeleton } from "@/components/ui/skeleton";
import { MeasurementForm } from "@/components/measurements/measurement-form";
@@ -78,7 +79,7 @@ export function VorsorgeDashboardCard() {
// the dashboard summary offering what the dedicated page withholds was the
// tell that this row had never been asked.
const { canManage } = useRecordCapabilities();
- const { data: reminders, isError } = useMeasurementReminders();
+ const { data: reminders, isError, refetch } = useMeasurementReminders();
// A query's `isLoading` is not a hydration-safe branch: TanStack reports the
// optimistic mount fetch on the client's very first render and cannot on the
@@ -153,6 +154,10 @@ export function VorsorgeDashboardCard() {
))}
+ ) : isError ? (
+ // A read failure must not read as "no upcoming reminders" โ a missed
+ // checkup is the harm behind that fall-through (ยง6).
+ refetch()} />
) : upcoming.length === 0 ? (