gildas-lormeau/SingleFile · error · Error

response && response.error && response.error.toString()

Error message

response && response.error && response.error.toString()

What it means

sendMessage() wraps browser.runtime.sendMessage for SingleFile's content fetch: if the background returns no response or a response with an .error field, it throws an Error whose message is the stringified response.error. This is the transport wrapper that converts background-side failures into exceptions in the content script.

Source

Thrown at src/lib/single-file/fetch/content/content-fetch.js:183

		const promise = new Promise((resolve, reject) => pendingResponses.set(requestId, { resolve, reject }));
		await sendMessage({ method: "singlefile.fetch", url, requestId, referrer: options.referrer, headers: options.headers });
		return promise;
	}
}

async function frameFetch(url, options) {
	const response = await sendMessage({ method: "singlefile.fetchFrame", url, frameId: options.frameId, referrer: options.referrer, headers: options.headers });
	return {
		status: response.status,
		headers: new Map(response.headers),
		arrayBuffer: async () => new Uint8Array(response.array).buffer
	};
}

async function sendMessage(message) {
	const response = await browser.runtime.sendMessage(message);
	if (!response || response.error) {
		throw new Error(response && response.error && response.error.toString());
	} else {
		return response;
	}
}

View on GitHub (pinned to 517fb7c5cf)

Solutions

  1. Read the stringified response.error in the thrown message — it is the background's original failure; fix that root cause
  2. Reload the page/tab to re-establish a valid browser.runtime channel after extension updates
  3. Ensure a runtime.onMessage listener always replies (or return true for async) so responses are never undefined
  4. Keep the MV3 service worker alive / retry the message with backoff when the response is undefined (worker wakeup race)

Example fix

// before
const response = await browser.runtime.sendMessage(message);
if (!response || response.error) {
  throw new Error(response && response.error && response.error.toString());
}
// after
const response = await browser.runtime.sendMessage(message);
if (!response) throw new Error("No response from extension background (context invalidated?)");
if (response.error) throw new Error(`Background error: ${response.error}`);
Defensive patterns

Strategy: try-catch

Validate before calling

if (typeof browser === "undefined" || !browser.runtime?.id) {
  throw new Error("Extension context invalidated — reload the page before messaging");
}

Type guard

function isValidResponse(res) {
  return res !== null && typeof res === "object" && !("error" in res);
}

Try / catch

try {
  const resource = await fetch(url, options);
} catch (e) {
  if (/No response|Extension context invalidated/i.test(e.message)) {
    await delay(500); // MV3 worker wakeup
    resource = await fetch(url, options); // retry once
  } else if (/Background error/i.test(e.message)) {
    console.error("Background failed:", e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: The background page/service worker throws while handling the fetch message and replies {error: ...}; the runtime returns undefined because no listener responded or the extension context was invalidated (update/reload).

Common situations: Extension background crashed or was reloaded mid-session (orphaned content script); background handler itself hit a network error and forwarded it via response.error; message sent before the background listener finished registering; MV3 service worker suspended.

Related errors


AI-assisted analysis of gildas-lormeau/SingleFile@517fb7c5cf (2026-09-01). Data as JSON: /api/errors/2838ef997daa55c8. Report an issue: GitHub.