{"record":{"id":"11691da7474ce781","repo":"gildas-lormeau/SingleFile","slug":"response-error-companion","errorCode":null,"errorMessage":"response.error + \" (Companion)\"","messagePattern":"response\\.error \\+ \" \\(Companion\\)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/companion.js","lineNumber":55,"sourceCode":"\t\treturn { enabled };\n\t}\n}\n\nasync function externalSave(pageData) {\n\tpageData.autoSaveExternalSave = false;\n\tlet response;\n\ttry {\n\t\tresponse = await browser.runtime.sendNativeMessage(\"singlefile_companion\", {\n\t\t\tmethod: \"externalSave\",\n\t\t\tpageData\n\t\t});\n\t} catch (error) {\n\t\tif (!error.message || !(error.message.includes(\"Native host has exited\") || error.message.includes(\"An unexpected error occurred\"))) {\n\t\t\tthrow error;\n\t\t}\n\t}\n\tif (response && response.error) {\n\t\tthrow new Error(response.error + \" (Companion)\");\n\t}\n}\n\nasync function save(pageData) {\n\tlet response;\n\ttry {\n\t\tresponse = await browser.runtime.sendNativeMessage(\"singlefile_companion\", {\n\t\t\tmethod: \"save\",\n\t\t\tpageData\n\t\t});\n\t} catch (error) {\n\t\tif (!error.message || !(error.message.includes(\"Native host has exited\") || error.message.includes(\"An unexpected error occurred\"))) {\n\t\t\tthrow error;\n\t\t}\n\t}\n\tif (response && response.error) {\n\t\tthrow new Error(response.error + \" (Companion)\");\n\t}","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/companion.js#L37-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify SingleFile Companion is installed and its native messaging host manifest is registered for this browser","Update Companion and the extension to matching versions","Read the message prefix (before \" (Companion)\") for the underlying native error and fix that cause","Fall back to the regular in-browser save path if Companion is unavailable"],"exampleFix":"// before\nawait singlefile.externalSave(pageData);\n// after\ntry {\n  await singlefile.externalSave(pageData);\n} catch (e) {\n  if (e.message.endsWith('(Companion)')) return fallbackInBrowserSave(pageData);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// no pre-call validation available; check Companion installation out of band\nconst companionReady = await isNativeHostRegistered();","typeGuard":null,"tryCatchPattern":"try { await externalSave(pageData); } catch (e) { if (e.message.endsWith('(Companion)')) fallback(e.message.replace(' (Companion)','')); else throw e; }","preventionTips":["Install/verify SingleFile Companion before enabling external saves","Keep Companion and extension versions in sync","Parse the '(Companion)' suffix to attribute failures correctly","Provide a non-Companion save fallback"],"tags":["native-messaging","companion","external-app"],"backgroundTag":"companion-native-host-error","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}