NativeScript/NativeScript · error · Error

Failed to execute 'send' on 'XMLHttpRequest': The object's s

Error message

Failed to execute 'send' on 'XMLHttpRequest': The object's state must be OPENED.

What it means

XMLHttpRequest.send() in @nativescript/core requires the request to be in the OPENED state (after a successful open() call) and not already sent. The implementation checks this.readyState !== OPENED || this._sendFlag and throws to mirror the browser spec, where send() on an uns opened or already-sent request is an InvalidStateError. It enforces the one-request-per-XHR lifecycle.

Source

Thrown at packages/core/xhr/index.ts:233

			this._errorFlag = true;
			this._sendFlag = false;
			this._setRequestError('abort');
		}

		if (this._readyState === this.DONE) {
			this._readyState = this.UNSENT;
		}
	}

	public send(data?: any) {
		this._errorFlag = false;
		this._response = null;
		this._responseTextReader = null;
		this._headers = null;
		this._status = null;

		if (this._readyState !== this.OPENED || this._sendFlag) {
			throw new Error("Failed to execute 'send' on 'XMLHttpRequest': " + "The object's state must be OPENED.");
		}

		if (isString(data) && this._options.method !== 'GET') {
			//The Android Java HTTP lib throws an exception if we provide a
			//a request body for GET requests, so we avoid doing that.
			//Browser implementations silently ignore it as well.
			this._options.content = data;
		} else if (data instanceof FormData) {
			this._options.content = (<FormData>data).toString();
		} else if (data instanceof Blob) {
			this.setRequestHeader('Content-Type', data.type);
			this._options.content = Blob.InternalAccessor.getBuffer(data);
		} else if (data instanceof ArrayBuffer) {
			this._options.content = data;
		}

		this._sendFlag = true;

View on GitHub (pinned to 6800aefa65)

Solutions

  1. Call xhr.open(method, url) before calling send().
  2. Create a fresh XMLHttpRequest instance for each request instead of reusing one.
  3. Guard with a state check: only send when xhr.readyState === xhr.OPENED and not already sent.
  4. If retrying, wrap the open+send sequence in a function that builds a new XHR each time.

Example fix

// before
const xhr = new XMLHttpRequest();
xhr.send(null); // throws

// after
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send(null);
Defensive patterns

Strategy: validation

Validate before calling

if (xhr.readyState === xhr.OPENED && !xhr._sendFlag) { xhr.send(data); }

Type guard

function canSend(xhr) { return xhr.readyState === xhr.OPENED; }

Try / catch

try { xhr.send(data); } catch (e) { if (String(e.message).includes("state must be OPENED")) { /* create new XHR, open, send */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling xhr.send() before calling xhr.open(); calling send() twice on the same XMLHttpRequest instance (the second call hits _sendFlag === true); calling send() after abort() or after the request reached DONE without resetting via open().

Common situations: Event-handler race where an async callback retries send() on the same object; copy-pasted code that forgets open(); wrapping send in retry logic without creating a new XHR instance; calling send from onreadystatechange handlers after completion.

Related errors


AI-assisted analysis of NativeScript/NativeScript@6800aefa65 (2026-08-30). Data as JSON: /api/errors/094174541225a431. Report an issue: GitHub.