Skip to content

AbrController _abandonRulesCheck can throw after destroy #7937

Description

@AmPlace

What version of Hls.js are you using?

v1.6.16 via https://cdn.jsdelivr.net/npm/hls.js@1/dist/hls.min.js. The same null-dereference path is present on the current master branch.

What browser and OS are you using?

This was reproduced using the then-current Stable Chrome on macOS in June 2026 (Chrome 149 Stable). The exact 149.0.7827.x patch number and macOS patch version were not retained.

It was not reproduced in Chrome on Windows or in Safari during the same debugging session.

Test stream

The issue was observed in a live IPTV player while rapidly switching HLS sources. The original application-side workaround and error description are public:

AmPlace/waveflow@e4fdbde

A standalone browser reproduction has not yet been isolated.

Configuration

{
  enableWorker: true,
  lowLatencyMode: false,
  liveDurationInfinity: true,
  liveSyncDuration: 20,
  liveMaxLatencyDuration: 55,
  maxBufferLength: 30,
  maxBufferHole: 0.5,
}

Steps to reproduce

  1. Start playback of a multi-level live HLS source.
  2. Rapidly switch sources, destroying the previous HLS instance.
  3. On macOS Chrome 149 Stable, an _abandonRulesCheck invocation was observed after the controller's hls reference had been released.

The exact browser scheduling or re-entrant path that leads to the post-destroy invocation has not been isolated.

A unit-level safety test can retain the callback reference, destroy the HLS instance, and invoke the callback:

const abandonRulesCheck = (abrController as any)._abandonRulesCheck;
hls.destroy();
expect(() => abandonRulesCheck()).not.to.throw();

This demonstrates the null-dereference path and verifies the guard, but does not reproduce the macOS browser timing.

Expected behavior

An ABR check that reaches a destroyed controller should return safely.

Actual behavior

Uncaught TypeError: Cannot read properties of null (reading 'autoLevelEnabled')
    at AbrController._abandonRulesCheck (abr-controller.ts:244)

Confirmed failure path

AbrController.destroy() clears its timer and releases references by setting this.hls to null. _abandonRulesCheck destructures autoLevelEnabled from hls without checking whether the controller has been destroyed.

The production exception confirms a post-destroy invocation, but the exact mechanism that invokes the callback after cleanup remains unisolated.

Suggested fix

Return early from _abandonRulesCheck when this.hls is null, with a regression test covering safe behavior after destroy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions