Skip to content

XMLHttpRequest: error steps not followed for abort()/network errors #2291

Description

@rexxars

Describe the bug

When a request is aborted (or fails with a network error) after the response headers have already been received, happy-dom does not run the specification's "request error steps" correctly:

  • readystatechange is dispatched after abort/error and loadend, instead of immediately after the ready state changes.
  • The previously received response (status, response headers, partially accumulated body) is never discarded, so xhr.status, xhr.getAllResponseHeaders() and similar still report data from the failed request even though the request state has moved to unsent/done.

In a real browser, the request error steps set the response to a network error and fire readystatechange before the abort/error/loadend events, so none of the failed request's data remains observable afterward.

To Reproduce
Steps to reproduce the behavior:

  1. Create an XMLHttpRequest against an endpoint that responds with headers immediately but streams the body slowly.
  2. Wait until the response headers have arrived (readyState 2, xhr.status already reflects e.g. 200).
  3. Call xhr.abort() before the body finishes.
  4. Inspect xhr.status, xhr.getAllResponseHeaders() and the order events were received in.
const xhr = new XMLHttpRequest();
const events = [];
['readystatechange', 'abort', 'loadend'].forEach((type) =>
  xhr.addEventListener(type, () => events.push(type))
);

xhr.open('GET', '/slow-body');
xhr.send();

// once headers have arrived:
xhr.abort();

// events fires ['abort', 'loadend', 'readystatechange'] - should be
// ['readystatechange', 'abort', 'loadend'].
// xhr.status still reports 200 and xhr.getAllResponseHeaders() still
// returns the aborted response's headers, even though the request was
// aborted and readyState is back to unsent.

https://stackblitz.com/edit/happy-dom-wrong-event-order?file=index.js

Expected behavior

On abort or network error, happy-dom should:

  1. Reset the response to a network error (so status becomes 0, headers/body/responseURL are cleared) before dispatching any events.
  2. Dispatch readystatechange first, then abort/error, then loadend.

Device and details:

  • OS: MacOS 26.6.1
  • Node version: 24.19.0
  • Package version: 20.11.2

Additional context

Relevant spec section: https://xhr.spec.whatwg.org/#request-error-steps

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions