Skip to content

fix: crash when editing a field + make app null-safe (strict TS) - #7

Merged
pythonsst merged 1 commit into
mainfrom
fix/preview-crash-stale-pages
Jun 27, 2026
Merged

fix: crash when editing a field + make app null-safe (strict TS)#7
pythonsst merged 1 commit into
mainfrom
fix/preview-crash-stale-pages

Conversation

@pythonsst

Copy link
Copy Markdown
Owner

The crash

You reported the app crashing when deleting/clearing the name. The error (from your screenshot):

TypeError: Cannot read properties of undefined (reading 'label')
  at renderRow (FloralTemplate.tsx:56)  ← row is undefined
  at nodeFor (FramedDoc.tsx)

Root cause

FramedDoc caches the paginated pages in React state, updated by an effect that runs after render. When you edit a field, the component re-renders with the new, shorter data but the old pages, which still reference row indices that no longer exist → sections[s].rows[r] is undefinedrow.label throws. Timing-sensitive, which is why it only reproduces with real layout measurement.

Fix (two independent layers)

  1. Cached pages are tagged with the data signature they were built from; a render only uses them when it still matches, else it lays out the current units. No stale indices, ever.
  2. nodeFor is null-safe — returns null for any missing section/row instead of dereferencing undefined.

Null-safety hardening (your "make it null-safe + fully typed" ask)

Enabled noUncheckedIndexedAccess (+ noImplicitOverride) — every array/object index is now T | undefined, so the compiler forces guards. This flag would have caught the crash at compile time. Fixed the 15 spots it surfaced:

  • paginate.ts / pdf.ts: guarded index access in loops.
  • templates registry + headerPresets: typed as non-empty tuples so [0] is always defined.
  • BiodataForm: coerce optional accordion state to boolean.

Verification

  • tsc --noEmit (strict + noUncheckedIndexedAccess): 0 errors
  • npm run lint clean · npm test 37/37 · next build green
  • Reproduced the delete-then-retype flow on Floral in a headless browser: no crash, no console errors.

🤖 Generated with Claude Code

…l-safety

Crash: "Cannot read properties of undefined (reading 'label')" in a template's
renderRow when you delete text from a field. FramedDoc caches the paginated
pages in state (updated by an effect after render); on the next render the new,
shorter data was laid out against the OLD pages, whose row indices no longer
existed -> sections[s].rows[r] was undefined.

Fix (two layers):
- Tag cached pages with the data signature they were built from and only use
  them when it still matches; otherwise lay out the current units directly.
- Make nodeFor null-safe: return null for any missing section/row instead of
  dereferencing undefined.

Null-safety hardening (so the compiler catches this class of bug):
- tsconfig: enable noUncheckedIndexedAccess + noImplicitOverride.
- paginate.ts / pdf.ts: guard array index access in loops.
- templates registry + headerPresets: typed as non-empty tuples so [0] is
  always defined.
- BiodataForm: coerce optional accordion open-state to boolean.

tsc (strict) clean, lint clean, 37 tests pass, build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
snapbiodata Ready Ready Preview, Comment Jun 27, 2026 10:43pm

@pythonsst
pythonsst merged commit d99454b into main Jun 27, 2026
3 checks passed
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