HarperFast / HarperFast/studio

[RUM] ResizeObserver loop burst on org overview — 86 unhandled errors in 3.5s (52% of all errors in 24h)

Open
#1,579 0 comments 0 reactions 0 assignees View on GitHub
rum
Dominant language
TypeScript
Stars
5
Forks
4
Avg merge
1d 8h
Merged PRs (30d)
40

Description

## Summary

A single session emitted **86 unhandled `ResizeObserver loop completed with undelivered notifications` errors in a 3.5-second window** on the organization overview page. This was **52% of all Studio RUM errors in the last 24h** (86 of 165) and is the top error by volume in the window.

Found during the daily Datadog RUM review (2026-07-29). Not previously reported — no open or closed issue mentions ResizeObserver.

## Datadog findings

| Field | Value |
| --- | --- |
| Message | `Uncaught "ResizeObserver loop completed with undelivered notifications."` |
| Type / source / handling | `Error` / `source` (window.onerror) / **unhandled** |
| Fingerprint | `v12.39675259B80C619002ABA15014685CEE` |
| Events | 86 |
| Window | 2026-07-29 12:40:44.641Z → 12:40:48.194Z (**3.55s**, ~24 errors/sec) |
| Sessions / users | 1 / 1 |
| View | `/$organizationId/` (org overview → [`ClustersList`](src/features/clusters/ClustersList.tsx)) |
| Referrer | `#//roles` — arrived by navigating from Organization Roles |
| Browser / OS | Chrome 150, Windows 10, Desktop |
| Viewport | **1280 × 631** (unusually short) |

### Rate of occurrence

This is a new, isolated burst rather than an ambient rate. Over the previous 7 days there was exactly **1** such error total; all 86 others landed in this one 3.55s window:

```
last 24h : 86
day 2–7 : 1 (cumulative)
```

### Stack

`window.onerror` gives no component stack, so RUM records only:

```
Error: ResizeObserver loop completed with undelivered notifications.
at undefined @ https://fabric.harper.fast/#/org-
```

## Why this is worth looking at

`ResizeObserver loop completed with undelivered notifications` is often dismissed as benign browser noise, and in low volumes it is. A burst of ~24/sec sustained for 3.5s is different: it means an observer callback kept mutating layout that the same observer watches, so the browser could not reach a stable layout within a frame. Practical consequences are dropped frames and layout thrash on the org overview page.

The short viewport (631px) is suggestive — the classic trigger for this loop is a **scrollbar oscillation**: content grows → scrollbar appears → available width shrinks → content reflows shorter → scrollbar disappears → repeat.

## Investigation notes so far

- [`ClustersList`](src/features/clusters/ClustersList.tsx) itself declares no `ResizeObserver`.
- The only app-level `ResizeObserver` in `src/` is [`HeatmapMatrix.tsx:360`](src/features/instance/status/analytics/primitives/HeatmapMatrix.tsx#L360), which is instance-status analytics and does **not** render on this route.
- So the observer is almost certainly inside a dependency — Radix UI primitives (`SubNavMenu`, tooltips, popovers) or Recharts' `ResponsiveContainer` — reacting to a container whose size our CSS makes non-idempotent.
- [`table.tsx:114–130`](src/components/ui/table.tsx#L114-L130) does synchronous `getBoundingClientRect()` width measurement; worth checking whether anything on this route drives it.

## Suggested next steps

1. Reproduce locally: org overview with several cluster cards, browser window sized to ~1280×631, navigate in from `/roles` (the recorded referrer — the loop may need the remount rather than a cold load).
2. If it reproduces, identify the oscillating element via a temporary `ResizeObserver` error breakpoint / `window.onerror` logpoint and fix the layout (typically pinning `scrollbar-gutter: stable` or removing a measured-width → layout-width cycle).
3. Only if it proves genuinely unreproducible and benign, consider suppressing it in [`shouldKeepEvent.ts`](src/integrations/datadog/shouldKeepEvent.ts) — deliberately **not** done in #1578, so the evidence stays visible.

## Related

- #1578 — filters unrelated third-party (Reo.dev) errors found in the same review.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the organization overview route from /roles at roughly 1280×631 with several cluster cards, then inspect src/features/clusters/ClustersList.tsx, src/components/ui/table.tsx, and the suspected dependency components. Use a temporary ResizeObserver error breakpoint or window.onerror logpoint to identify the oscillating element. Done means the layout no longer produces the burst without suppressing the error in shouldKeepEvent.ts.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, observability, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.