gildas-lormeau/SingleFile · error · Error

response.error + " (Companion)"

Error message

response.error + " (Companion)"

What it means

externalSave relays page data to the SingleFile Companion native application. When the native host responds with an error field, the message is re-thrown suffixed with " (Companion)" so callers know the failure came from the Companion, not the extension itself.

Source

Thrown at src/core/bg/companion.js:55

		return { enabled };
	}
}

async function externalSave(pageData) {
	pageData.autoSaveExternalSave = false;
	let response;
	try {
		response = await browser.runtime.sendNativeMessage("singlefile_companion", {
			method: "externalSave",
			pageData
		});
	} catch (error) {
		if (!error.message || !(error.message.includes("Native host has exited") || error.message.includes("An unexpected error occurred"))) {
			throw error;
		}
	}
	if (response && response.error) {
		throw new Error(response.error + " (Companion)");
	}
}

async function save(pageData) {
	let response;
	try {
		response = await browser.runtime.sendNativeMessage("singlefile_companion", {
			method: "save",
			pageData
		});
	} catch (error) {
		if (!error.message || !(error.message.includes("Native host has exited") || error.message.includes("An unexpected error occurred"))) {
			throw error;
		}
	}
	if (response && response.error) {
		throw new Error(response.error + " (Companion)");
	}

View on GitHub (pinned to 517fb7c5cf)

Solutions

  1. Verify SingleFile Companion is installed and its native messaging host manifest is registered for this browser
  2. Update Companion and the extension to matching versions
  3. Read the message prefix (before " (Companion)") for the underlying native error and fix that cause
  4. Fall back to the regular in-browser save path if Companion is unavailable

Example fix

// before
await singlefile.externalSave(pageData);
// after
try {
  await singlefile.externalSave(pageData);
} catch (e) {
  if (e.message.endsWith('(Companion)')) return fallbackInBrowserSave(pageData);
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// no pre-call validation available; check Companion installation out of band
const companionReady = await isNativeHostRegistered();

Try / catch

try { await externalSave(pageData); } catch (e) { if (e.message.endsWith('(Companion)')) fallback(e.message.replace(' (Companion)','')); else throw e; }

Prevention

When it happens

Trigger: externalSave called while the Companion native app is unreachable, misconfigured, rejects the save (e.g. bad destination, auth issue), or its native messaging host reports an error in the response payload.

Common situations: Companion not installed or native messaging host manifest missing; Companion version mismatch with the extension; save destination (folder/credential) rejected by the app; native host crashed mid-save.


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