Skip to content

hotfix: IntervalHeatmap null-payload render crash (#150 regression)#166

Merged
delabrcd merged 1 commit into
mainfrom
hotfix/interval-heatmap-null-payload
Jun 22, 2026
Merged

hotfix: IntervalHeatmap null-payload render crash (#150 regression)#166
delabrcd merged 1 commit into
mainfrom
hotfix/interval-heatmap-null-payload

Conversation

@delabrcd

Copy link
Copy Markdown
Owner

Production hotfix for a client-side crash introduced by #150 (batch 3, v0.40.2).

Problem

IntervalHeatmap.tsx passed a chart subtree to <IntervalWidgetBody> that dereferenced payload!.grid/payload!.rowLabels. React evaluates children eagerly when the component renders — before IntervalWidgetBody short-circuits to the loading skeleton. During the initial loading tick useIntervalPayload returns payload === null, so payload!.grid threw TypeError: Cannot read properties of null (reading 'grid') at render time, taking down the entire dashboard ("Application error: a client-side exception has occurred").

It only manifests when the heatmap widget is actually mounted (a fresh/default layout, or a saved layout that includes it — the operator's prod layout did). Unit tests + a happy-path staging screenshot missed it because staging's saved layout didn't include the heatmap. Reproduced on staging by clearing the saved layout (→ default layout mounts the interval widgets) → same crash.

Fix

Gate the populated subtree on {payload && (…)} and drop the ! assertions, so children is falsy during loading and IntervalWidgetBody renders its skeleton. useIntervalPayload + IntervalWidgetBody unchanged. Siblings audited: IntervalLoadShape + IntervalHistory guard their payload in useMemo (if (!state || 'error' in state) return []) and are safe — no change.

Verification

  • Docker test stage: 67 files / 973 tests. Production builder (lint+typecheck+build): green.
  • Lead will confirm the fix on staging against the exact repro (clear layout → mount heatmap → expect skeleton, not crash) before release.

Prod was rolled back to v0.40.1 to restore service; this ships as v0.40.3.

The #150 refactor onto useIntervalPayload + IntervalWidgetBody left the
heatmap's chart subtree dereferencing payload!.grid / payload!.rowLabels.
React evaluates the children passed to IntervalWidgetBody eagerly, BEFORE
the wrapper decides to render the loading skeleton, so during the initial
loading tick (payload === null) this threw an unguarded render-time
TypeError that took the whole dashboard down ("Application error: a
client-side exception has occurred"), not just the widget.

Wrap the populated subtree in {payload && ( ... )} and drop the non-null
assertions so payload is dereferenced only when present; while loading/
error/empty, children is falsy and IntervalWidgetBody shows its
skeleton/empty as intended. Behavior otherwise identical.

Audited the two sibling widgets the #150 refactor touched: IntervalLoadShape
dereferences payload only inside guarded derivations (!state || 'error' in
state) so its eager children are safe; IntervalHistory keeps its own SWR
state and was not moved onto the hook, also safe.
@delabrcd delabrcd merged commit cbc328b into main Jun 22, 2026
6 checks passed
@delabrcd delabrcd deleted the hotfix/interval-heatmap-null-payload branch June 22, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant