Chrome Extension with injected Javascript – Cannot read properties of undefined (reading 'sendMessage')

Chrome Extension with injected Javascript – Cannot read properties of undefined (reading 'sendMessage')

Problem Description:

I have a script that I inject in the DOM and I want to send messages to my service worker in the background. I am getting an error and I don’t understand why.

Here is my background.js file:

chrome.runtime.onMessage.addListener((req, sender, sendRes) => {
  console.log('this has worked', req, sender, sendRes('this worked'));
  return true;

Here is my inject.js file that injects the injected.js (see below) code:

const s = document.createElement('script');
s.src = chrome.runtime.getURL('injected.js');
s.onload = function () {
(document.head || document.documentElement).appendChild(s);


console.log('fetch interceptor started');
const { fetch: origFetch } = window;
chrome.runtime.sendMessage({ works: 'This worked at least' }, (res) => console.log(res)); // Error is thrown immediately
window.fetch = async (...args) => {
  const response = await origFetch(...args);

  const url = new URL(args[0].url);
  //   sendMessageToBackground({ pathname, ...url.searchParams }); // not in use because it throws error at the top already
    .then(async (body) => await sendMessageToBackground({ pathname, body }))
    .catch((err) => console.error(err));

  return response;

async function sendMessageToBackground(msg) {
  const res = await chrome.runtime.sendMessage(msg);
  console.log('result message', res);
  console.log('msg', msg);

manifest.json in case required:

"permissions": ["storage", "activeTab", "scripting", "webRequest"],
  "host_permissions": ["*"],
  "manifest_version": 3,
  "background": {
    "service_worker": "background.js"
  "content_scripts": [
      "matches": ["*"],
      "run_at": "document_start",
      "js": ["inject.js"]
  "web_accessible_resources": [{ "resources": ["injected.js"], "matches": ["*"] }],

Solution – 1

By injecting a content script declaratively or in a programmed way through the methods allowed by the "scripting" andor "tabs" permissions, you bring to the web page a set of objects belonging to the world of extensions to which you would normally not be able to access.

Therefore, the inject.js script will be able to access these objects (in your case chrome.runtime), while the injectED.js script will not.

I don’t know what purpose your Chinese box system has, but I would try to skip inject.js and inject injectED.js declaratively.

For the await speech together with .then, in my opinion there are no contraindications (at least at first sight).
I’ve written routines before where I use this mix and never had a issue.

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.