Skip to content

Add per-slot error attribution for instant validation using slot markers and config depth preference#91610

Open
gnoff wants to merge 1 commit intocanaryfrom
jstory/per-slot-config-attribution
Open

Add per-slot error attribution for instant validation using slot markers and config depth preference#91610
gnoff wants to merge 1 commit intocanaryfrom
jstory/per-slot-config-attribution

Conversation

@gnoff
Copy link
Contributor

@gnoff gnoff commented Mar 18, 2026

When a validation boundary spans multiple parallel slots, errors were previously attributed to whichever unstable_instant config was found first during tree iteration — which varied between turbopack and webpack. This made the "Caused by: Instant Validation" source non-deterministic and sometimes pointed to the wrong slot's config.

This adds a SlotMarker client component that wraps each slot's content at fork points (where parallel routes > 1). The marker's dynamically-named inner function appears in the SSR component stack, allowing resolveInstantStack to identify which slot an error belongs to and look up that slot's config. When a slot has no config, it falls back to slotStacks[0] (the root config).

The root config is now selected by config depth preference rather than first-found. configDepth tracks how many URL-consuming segments deep a config was found, with deeper configs preferred as more specific. At equal depth, the children slot is preferred over named slots. This ensures deterministic attribution regardless of bundler iteration order.

Key changes:

  • SlotMarker component in boundary-impl.tsx takes a name prop and lazily creates named inner functions cached by name
  • slotStacks array replaces the singleton createInstantStack on InstantValidationState (index 0 = root config, 1+ = per-slot)
  • configDepth on TreeResult only counts URL-consuming segments — synthetic segments like (SLOT), PAGE, and route groups don't contribute
  • resolveInstantStack parses component stacks for slot markers and maps to the correct config
  • wrapSlotsWithMarkers called at every fork in both buildSharedTreeSeedData and buildNewTreeSeedData

…ers and config depth preference

When a validation boundary spans multiple parallel slots, errors were previously attributed to whichever unstable_instant config was found first during tree iteration — which varied between turbopack and webpack. This made the "Caused by: Instant Validation" source non-deterministic and sometimes pointed to the wrong slot's config.

This adds a SlotMarker client component that wraps each slot's content at fork points (where parallel routes > 1). The marker's dynamically-named inner function appears in the SSR component stack, allowing resolveInstantStack to identify which slot an error belongs to and look up that slot's config. When a slot has no config, it falls back to slotStacks[0]  (the root config).

The root config is now selected by config depth preference rather than first-found. configDepth tracks how many URL-consuming segments deep a config was found, with deeper configs preferred as more specific. At equal depth, the children slot is preferred over named slots. This ensures deterministic attribution regardless of bundler iteration order.

Key changes:
- SlotMarker component in boundary-impl.tsx takes a name prop and lazily creates named inner functions cached by name
- slotStacks array replaces the singleton createInstantStack on InstantValidationState (index 0 = root config, 1+ = per-slot)
- configDepth on TreeResult only counts URL-consuming segments — synthetic segments like (__SLOT__), __PAGE__, and route groups don't contribute
- resolveInstantStack parses component stacks for slot markers and maps to the correct config
- wrapSlotsWithMarkers called at every fork in both buildSharedTreeSeedData and buildNewTreeSeedData
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Mar 18, 2026

Tests Passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants