#740·vConsole

Uncaught TypeError when assigning null to xhr.onreadystatechange/onprogress (breaks hls.js abort)

Author: cyhanoCreated Sep 15, 2026Updated Sep 15, 2026

Description

Libraries like hls.js clear XHR event callbacks before aborting in-flight requests (see XhrLoader.abortInternal in hls.js):

javascript
xhr.onreadystatechange = null;
xhr.onprogress = null;
xhr.abort();

With vConsole enabled, this throws an uncaught TypeError, because the XHR proxy wraps whatever value is assigned to onreadystatechange / onabort / ontimeout without a null check — the wrapper later calls value.apply(...) on null.

src/network/xhr.proxy.ts (still present on current master):

typescript
protected setOnReadyStateChange(target: T, key: string, value) {
  ...
  Reflect.set(target, key, function () {
    ...
    value.apply(target, args);   //  value may be null
  });
}
// setOnAbort / setOnTimeout have the same problem

Assigning null to these callbacks is a legitimate, spec-compliant way to remove them, so the proxy should pass null through instead of wrapping it.

Steps to reproduce

xml
<script src="https://unpkg.com/[email protected]/dist/vconsole.min.js"></script>
<script>
  new VConsole();
  var xhr = new XMLHttpRequest();
  xhr.open('GET', '/');                 // any URL
  xhr.onreadystatechange = function () {};
  xhr.send();
  xhr.onreadystatechange = null;        // how hls.js abortInternal cleans up
  xhr.onprogress = null;
  xhr.abort();                          // → Uncaught TypeError: Cannot read properties of null (reading 'apply')
</script>

Running the exact same code without vConsole produces no error (verified side by side).

Real-world impact

Any page playing HLS video via hls.js throws this on every stream switch / stop / destroy:

Uncaught TypeError: Cannot read property 'apply' of null
    at XMLHttpRequest.<anonymous> (vconsole.js)
    at t.r.abortInternal (hls.min.js)
    at t.abort (hls.min.js)
    at e.t.abort (hls.min.js)
    at t.r.stopLoad (hls.min.js)
    ...

Environment

  • vConsole version: 3.15.1 (latest release; null check also missing on current master)
  • Browser: any (reproduced in Chrome)

Suggested fix

Pass null/undefined through instead of wrapping it, in all three setters:

typescript
protected setOnReadyStateChange(target: T, key: string, value) {
  if (!value) return Reflect.set(target, key, value);
  ...
}