ovity/octotree · error · Error

promisify: fn does not have ${method} method

Error message

promisify: fn does not have ${method} method

What it means

promisify(fn, method) in core.storage.js wraps a callback-style storage backend (chrome.storage-based class) into a Promise API by checking that fn has the given method before wrapping it. If the passed object lacks the method, it throws 'promisify: fn does not have <method> method' synchronously from the storage controller constructor.

Source

Thrown at src/core.storage.js:156

            'If the local storage for this domain is full, please clean it up and try again.';
          console.error(msg, e);
        }
        resolve();
      }
    });
  }

  _removeLocal (key) {
    return new Promise((resolve) => {
      localStorage.removeItem(key);
      resolve();
    });
  }
}

function promisify(fn, method) {
  if (typeof fn[method] !== 'function') {
    throw new Error(`promisify: fn does not have ${method} method`);
  }

  return function(...args) {
    return new Promise(function(resolve, reject) {
      fn[method](...args, function(res) {
        if (chrome.runtime.lastError) {
          reject(chrome.runtime.lastError);
        } else {
          resolve(res);
        }
      });
    });
  };
}

window.extStore = new ExtStore(STORE, DEFAULTS)

View on GitHub (pinned to 470747c700)

Solutions

  1. Implement the missing method on the storage object passed to the constructor (match the exact name in the error message)
  2. Pass the correct storage backend class instance/dependency wiring instead of a partial or mock object
  3. Check for typos or renamed methods between your backend and what promisify expects (get, set, remove, etc.)
  4. Pin/align your custom backend with the version of Octotree in use, adding any newly required methods

Example fix

// before
const store = { get(key, cb) { /* ... */ } };
new Storage(store); // throws: promisify: fn does not have set method

// after
const store = {
  get(key, cb) { /* ... */ },
  set(obj, cb) { /* ... */ },
  remove(key, cb) { /* ... */ }
};
new Storage(store);
Defensive patterns

Strategy: validation

Validate before calling

const REQUIRED = ['get', 'set', 'remove'];
const missing = REQUIRED.filter((m) => typeof store[m] !== 'function');
if (missing.length) {
  throw new Error(`storage backend missing methods: ${missing.join(', ')}`);
}

Type guard

function isValidStorageBackend(fn) {
  return typeof fn === 'object' && fn !== null &&
    ['get', 'set', 'remove'].every((m) => typeof fn[m] === 'function');
}

Try / catch

let storage;
try {
  storage = new Storage(backend);
} catch (err) {
  if (/^promisify: fn does not have /.test(err.message)) {
    console.error('Storage backend is missing a required method:', err.message);
    storage = new Storage(chromeStorageFallback);
  } else { throw err; }
}

Prevention

When it happens

Trigger: The storage controller constructor calls promisify(fn, 'get'|'set'|'remove'|...) with a backend object that is missing one of the required methods — e.g. a custom/partial storage implementation, a wrongly injected dependency, or a renamed method after a chrome.* API or version change.

Common situations: Implementing a custom storage backend (e.g. for Firefox or tests) that omits a required method like remove() or get(); passing the wrong object (undefined/mock) as the storage dependency; an Octotree version bump adding a new promisified method that custom backends don't provide.


AI-assisted analysis of ovity/octotree@470747c700 (2026-08-31). Data as JSON: /api/errors/c0f2c0fb831da1e2. Report an issue: GitHub.