remix-run/remix · warning

${cascadingComponentUpdateCount} cascading component updates

Error message

${cascadingComponentUpdateCount} cascading component updates detected in one event loop turn. Consider reducing hydration regions. Components: ${formatComponentCounts(cascadingComponentNameCounts)}

What it means

The UI scheduler warns once per session when the number of cascading component updates in a single event loop turn exceeds CASCADING_UPDATE_WARN_THRESHOLD. Cascades mean one update triggers others (often via overlapping hydration regions), causing excess render work per tick.

Source

Thrown at packages/ui/src/runtime/scheduler.ts:122

  function trackCascadingUpdate(vnode: CommittedComponentNode): boolean {
    cascadingComponentUpdateCount++

    let componentName = getComponentName(vnode)
    cascadingComponentNameCounts.set(
      componentName,
      (cascadingComponentNameCounts.get(componentName) ?? 0) + 1,
    )

    let componentUpdateCount = (cascadingComponentUpdateCounts.get(vnode) ?? 0) + 1
    cascadingComponentUpdateCounts.set(vnode, componentUpdateCount)
    scheduleCounterReset()

    if (
      !warnedAboutCascadingUpdates &&
      cascadingComponentUpdateCount >= CASCADING_UPDATE_WARN_THRESHOLD
    ) {
      warnedAboutCascadingUpdates = true
      console.warn(
        `${cascadingComponentUpdateCount} cascading component updates detected in one event loop turn. Consider reducing hydration regions. Components: ${formatComponentCounts(cascadingComponentNameCounts)}`,
      )
    }

    if (componentUpdateCount > MAX_CASCADING_COMPONENT_UPDATES) {
      let error = new Error(
        `handle.update() infinite loop detected in ${componentName} after ${componentUpdateCount} cascading updates. Components: ${formatComponentCounts(cascadingComponentNameCounts)}`,
      )
      dispatchError(error)
      return false
    }

    return true
  }

  function flush() {
    if (flushing) return
    flushing = true

View on GitHub (pinned to 9696913134)

Solutions

  1. Split large hydration regions into smaller ones so each flush does less cascading work
  2. Move fan-out state into fewer, coarser subscriptions or a store read during render
  3. Memoize/isolate subtrees so unrelated components don't update together

Example fix

// before
<div data-hydrate="whole-page">...</div>
// after
<div data-hydrate="header">...</div>
<div data-hydrate="main">...</div>
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: A flush() turn in which many components schedule updates in reaction to other updates — commonly large hydration regions where hydrated components each trigger further component updates.

Common situations: Apps with very large or heavily nested hydration regions, wide component trees hydrated at once, or state changes that fan out through many subscribed components in one tick.

Related errors


AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27). Data as JSON: /api/errors/dc550c1b44d2148b. Report an issue: GitHub.