Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Video player fails with NotAllowedError + $state crash on feed navigation (Next.js 16 + Swiper) #1753

@floatrx

Description

@floatrx

Environment

Package Version
next 16.1.6 (Turbopack)
@vidstack/react ^1.12.13
react / react-dom 19.2.4
swiper ^12.1.2
Browser Chrome (desktop & mobile)

Description

The vertical video feed occasionally fails to play videos. Two errors appear in sequence:

1. NotAllowedError: play() failed because the user didn't interact with the document first

The browser autoplay policy blocks play() when the page loads or after Swiper slide transitions — even though <MediaPlayer> has muted set initially.

Current workaround: catch the error and retry with forced mute:

player.play().catch((err: unknown) => {
  if ((err as { name?: string })?.name === 'NotAllowedError') {
    player.muted = true;
    setMuted(true);
    player.play().catch(() => {});
  }
});

This works most of the time but not always (e.g., when the tab regains focus or on certain mobile browsers).

2. Uncaught TypeError: this.$state[prop2] is not a function

This occurs after the NotAllowedError, suggesting that Vidstack's internal Maverick signal store gets into a broken state. It happens when:

  • Swiper rapidly destroys/remounts <MediaPlayer> components during fast swiping
  • The src prop is cleared (set to "") — destroying the signal store
  • The player component unmounts while an async play() promise is still pending

Related: #1549 — similar signal store crash on navigation/remount with React Router.

Steps to Reproduce

  1. Open the video feed page
  2. Quickly swipe through several videos (vertical Swiper)
  3. Observe console errors — NotAllowedError followed by $state[prop2] is not a function
  4. The affected slide shows a black screen; the player is unrecoverable without remount

Current Mitigations

src is never cleared — preload="none" used for far slides to keep the signal store alive:

/*
 * Memory management by distance:
 *  0 (active)   — full preload, play with sound
 *  1 (adjacent) — full preload, paused — ready to play instantly on swipe
 *  2+ (far)     — src kept but preload="none" — browser won't buffer,
 *                 Vidstack signal store stays alive → no $state errors
 *
 * NOTE: src is NEVER cleared — setting src="" destroys Vidstack's internal
 * Maverick signal system causing "this.$state[prop2] is not a function".
 */
const src = episode.videoUrl ?? '';
const preload = distance <= 1 ? 'auto' : 'none';
  • NotAllowedError is caught and retried with forced mute (see above)
  • player.pause() is wrapped in try/catch to prevent cascading errors

Expected Behavior

  • Videos should play reliably on slide activation without console errors
  • Player state should not crash when components are rapidly mounted/unmounted by Swiper

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions