{"record":{"id":"dbf719b2e2f56aa7","repo":"gildas-lormeau/SingleFile","slug":"cannot-identify-the-extension-requesting-singlefil","errorCode":null,"errorMessage":"Cannot identify the extension requesting SingleFile capture","messagePattern":"Cannot identify the extension requesting SingleFile capture","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/core/bg/external-capture-permissions.js","lineNumber":50,"sourceCode":"let requestId = 0;\n\nexport {\n\tonMessage,\n\trequestPermission\n};\n\nif (browser.tabs.onRemoved) {\n\tbrowser.tabs.onRemoved.addListener(tabId => {\n\t\tArray.from(pendingRequests.values())\n\t\t\t.filter(request => request.tabId == tabId)\n\t\t\t.forEach(request => resolveRequest(request, false));\n\t});\n}\n\nasync function requestPermission(sender, message = {}) {\n\tconst extensionId = sender && sender.id;\n\tif (!extensionId) {\n\t\tthrow new Error(\"Cannot identify the extension requesting SingleFile capture\");\n\t}\n\tconst permissions = await config.getExternalCapturePermissions();\n\tif (permissions.allowedExtensionIds.includes(extensionId)) {\n\t\treturn true;\n\t}\n\tif (permissions.deniedExtensionIds.includes(extensionId)) {\n\t\treturn false;\n\t}\n\tconst { request, created } = getOrCreatePendingRequest(extensionId, sender, message);\n\tif (created) {\n\t\tawait openOptionsPage(request);\n\t}\n\treturn request.promise;\n}\n\nasync function onMessage(message, sender) {\n\tif (!isOptionsPageSender(sender)) {\n\t\tthrow new Error(\"Unauthorized sender\");","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/gildas-lormeau/SingleFile/blob/517fb7c5cf2096d89933b747e862d8ecf616a9f9/src/core/bg/external-capture-permissions.js#L32-L68","documentation":"requestPermission in external-capture-permissions.js validates that the incoming message originates from a browser extension with a sender.id. If sender is missing or has no id, it throws this error because the caller's extension cannot be identified or checked against the allow/deny permission lists.","triggerScenarios":"An external runtime.onMessage / onMessageExternal event delivers a request to initiate a SingleFile capture where the `sender` object is absent or `sender.id` is undefined (e.g. message from a web page, service worker context without id, or malformed call).","commonSituations":"A web page or non-extension script messaging SingleFile directly; a third-party integration calling the external API incorrectly; browser (e.g. Safari/Firefox variant) delivering a sender shape without id; test harness invoking requestPermission without a sender.","solutions":["Ensure the caller is a real extension and calls chrome.runtime.sendMessage(EXTENSION_ID, ...) so sender.id is populated","Update the integrating extension to the latest version that sends proper sender metadata","Verify the message route is onMessageExternal (external messages) not an internal handler","If you control the caller, pass a valid sender object when invoking requestPermission"],"exampleFix":"// before\nchrome.runtime.sendMessage(msg); // from a page, no sender.id\n// after\nchrome.runtime.sendMessage(SINGLEFILE_EXTENSION_ID, msg); // sender.id set","handlingStrategy":"validation","validationCode":"// caller-side check before messaging SingleFile\nchrome.runtime.sendMessage(SINGLEFILE_ID, { method: 'initiateCapture' }, response => {\n  if (chrome.runtime.lastError) { /* handle: sender.id missing or not allowed */ }\n});","typeGuard":"function hasExtensionSender(sender) {\n  return Boolean(sender && typeof sender.id === 'string' && sender.id.length > 0);\n}","tryCatchPattern":"try {\n  await requestPermission(sender, message);\n} catch (error) {\n  if (error.message.includes('Cannot identify the extension')) {\n    // reject the request: caller is not an identifiable extension\n  } else { throw error; }\n}","preventionTips":["Only send external capture requests from real extension contexts","Use runtime.onMessageExternal and rely on browser-provided sender","Never synthesize or omit the sender argument in tests against this API","Register the requesting extension's id in allowedExtensionIds beforehand"],"tags":["permissions","extension","sender-id","validation"],"backgroundTag":"unknown-extension-sender","analyzedSha":"517fb7c5cf2096d89933b747e862d8ecf616a9f9","analyzedAt":"2026-09-01T10:05:25.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}