Leveling Up Error Handling: Why We Refactored Flowplayer’s Error System

We’re excited to share a recent improvement to Flowplayer’s architecture that makes error handling more robust, predictable, and developer-friendly! This seemingly small change makes a big difference in real-world applications, so let’s dive into why we made this change and how it benefits your development workflow.

The Challenge: When Error Events Collide

Our previous approach to error handling mapped various errors from different sources (hls.js, WebRTC, etc.) to the browser-native error event on the HTMLVideoElement. The challenge? This element already throws its own MediaError natively.

This created an unfortunate situation where two different types of errors were using the same event, something which the Playback team has been unsatisfied with as a design decision for a very long time:

// Old approach - mapping everything to the native error event
videoElement.dispatchEvent(new ErrorEvent('error', { 
  error: someCustomErrorObject 
}));

// Meanwhile, the browser is also doing this with completely different error structures
videoElement.dispatchEvent(new ErrorEvent('error', { 
  error: new MediaError(/* browser native error */) 
}));

Error handling became unnecessarily complex. Developers had to write extra code to distinguish between different error types with inconsistent structures. Additionally browser vendors implement this event slightly differently, which required a significant amount of domain-knowledge to handle sufficiently, which isn’t in line with the “it just works” experience we strive for!

The Solution: A Custom Event for Better Control

We’ve implemented a cleaner approach by creating a dedicated STANDARD_ERROR event to handle our own errors without interfering with the browser’s native error events. Think of it as giving each type of error its own lane on the highway!

// New approach - using a custom event for our own errors
videoElement.dispatchEvent(new CustomEvent(flowplayer.events.STANDARD_ERROR, { 
  detail: {
    code: errorCode,
    message: errorMessage,
    source: errorSource,
    // Additional structured data...
  }
}));

// Browser still handles its own errors separately
// videoElement.dispatchEvent(new ErrorEvent('error', { ... }));

As a bonus, we’ve also adopted the Streaming Video Technology Alliance’s standardized player error codes (SVTA-2070). Because if there’s one thing developers love more than fixing errors, it’s knowing exactly which error they’re fixing!

Benefits: A Better Developer Experience

  1. Clear distinction between sources: Developers can easily tell if an error came from the browser or from our player. No more error identity crises!
  2. Structured error data: Our STANDARD_ERROR event includes consistent properties across all error sources, making handling errors across different components much more predictable.
  3. No event collision: We no longer interfere with the browser’s native error handling, creating a cleaner separation of concerns.
  4. Better debugging: When issues arise (and in video streaming, they certainly will!), developers can more easily identify the source of problems.
  5. Standardized error codes: By adopting the SVTA-2070 specification, our errors follow industry best practices, making knowledge transferable across different video players.

Implementation Example

Here’s how a developer might handle these different errors with our new approach:

// Handle browser native errors
// These are also mapping to `flowplayer.events.STANDARD_ERROR` 
// so all of your error handling can be done in one place.
videoElement.addEventListener('error', (event) => {
  const mediaError = event.target.error;
  console.error('Browser native error:', mediaError.code, mediaError.message);
});

// Handle Flowplayer errors - using the enum instead of a string literal
videoElement.addEventListener(flowplayer.events.STANDARD_ERROR, (event) => {
  const { code, message, resource } = event.detail;
  console.error(`error from ${resource}:`, code, message);
  
  // SVTA error codes are categorized for easier handling
  // Since the error codes are strings, we use string comparison
  if (code.startsWith('1')) {
    return console.error("Network-related error detected");
  }

  if (code.startsWith('4')) {
    return console.error("DRM error detected");
  }
});

Conclusion

This refactoring represents our ongoing commitment to improving the developer experience with Flowplayer. While it might seem like a small change, these kinds of thoughtful architectural decisions add up to make development smoother and more enjoyable.

By separating our error events from native browser events and adopting industry standards, we’ve made debugging easier and error handling more consistent. It’s part of our philosophy that the best code is not just powerful—it’s also a pleasure to work with.

Next time you’re implementing error handling with Flowplayer, you’ll hopefully appreciate this little quality-of-life improvement. After all, in video streaming, errors are inevitable—but dealing with them doesn’t have to be painful.

Search Wowza Resources

Categories

Subscribe

Follow Us

Categories

About Benjamin Clos

Benjamin Clos is a Team Lead at Wowza Flowplayer, guiding the team responsible for one of the web's most versatile and lightweight HTML5 video players. With deep expertise in front-end video technologies, Benjamin leads efforts to create seamless playback experiences across devices. His team focuses on player customization, UI optimization, and implementing advanced features like adaptive bitrate playback, ensuring videos start quickly and play smoothly regardless of network conditions. As a technical leader within Flowplayer's development organization, Benjamin oversees the player's extensible plugin architecture that powers features from interactive overlays to sophisticated ad insertion. Under his guidance, the team delivers engaging video experiences with minimal load times and maximum compatibility—critical factors in today's attention-scarce digital landscape.