petkaantonov/bluebird · error · TypeError
Cannot promisify an API that has normal methods with '%s'-su
Error message
Cannot promisify an API that has normal methods with '%s'-suffix
See http://goo.gl/MqrFmX
What it means
`Promise.promisifyAll` cannot promisify an object that contains both a method named `fooAsync` (matching the suffix) and a plain method `foo`, because generating `fooAsync` would collide with the existing normal method. The `checkValid` helper (src/promisify.js:59) detects this and throws.
Source
Thrown at src/promisify.js:59
}
}
function hasPromisified(obj, key, suffix) {
var val = util.getDataPropertyOrDefault(obj, key + suffix,
defaultPromisified);
return val ? isPromisified(val) : false;
}
function checkValid(ret, suffix, suffixRegexp) {
// Verify that in the list of methods to promisify there is no
// method that has a name ending in "Async"-suffix while
// also having a method with the same name but no Async suffix
for (var i = 0; i < ret.length; i += 2) {
var key = ret[i];
if (suffixRegexp.test(key)) {
var keyWithoutAsyncSuffix = key.replace(suffixRegexp, "");
for (var j = 0; j < ret.length; j += 2) {
if (ret[j] === keyWithoutAsyncSuffix) {
throw new TypeError(PROMISIFICATION_NORMAL_METHODS_ERROR
.replace("%s", suffix));
}
}
}
}
}
function promisifiableMethods(obj, suffix, suffixRegexp, filter) {
var keys = util.inheritedDataKeys(obj);
var ret = [];
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var value = obj[key];
var passesDefaultFilter = filter === defaultFilter
? true : defaultFilter(key, value, obj);
if (typeof value === "function" &&
!isPromisified(value) &&
!hasPromisified(obj, key, suffix) &&View on GitHub (pinned to c220cfe480)
Solutions
- Use a different suffix that doesn't collide: `Promise.promisifyAll(obj, { suffix: 'Promised' })`.
- Pass a `filter` to exclude the conflicting methods from promisification.
- Promisify only specific methods manually with `Promise.promisify`.
Example fix
// before
Promise.promisifyAll(fs); // fs has read and readAsync
// after
Promise.promisifyAll(fs, { suffix: 'Promised' }); Defensive patterns
Strategy: validation
Validate before calling
const keys = Object.keys(target).filter(k => typeof target[k] === 'function');
const suffixed = keys.filter(k => k.endsWith('Async')).map(k => k.slice(0, -'Async'.length));
if (suffixed.some(base => keys.includes(base))) {
throw new Error('promisifyAll suffix conflict detected');
}
Promise.promisifyAll(target, { suffix: 'Async' }); Try / catch
try {
Promise.promisifyAll(target);
} catch (e) {
if (String(e).includes('normal methods')) {
target = Promise.promisifyAll(target, { suffix: 'Promised' });
} else throw e;
} Prevention
- Inspect target method names for existing suffix collisions before promisifyAll.
- Use a distinctive suffix like 'Promised' in mixed APIs.
- Narrow promisification with a filter function.
When it happens
Trigger: `Promise.promisifyAll(obj)` where obj has methods `read` and `readAsync` with default 'Async' suffix; using a custom suffix that collides similarly (`suffix: 'Sync'` on an API with `readSync` and `read`).
Common situations: Promisifying libraries that already ship async-suffixed methods (some fs wrappers, AWS clients); switching suffixes without checking existing method names.
Related errors
- expecting a function but got %s
- Object %s has no method '%s'
- onCancel must be a function, got: %s
- generatorFunction must be a function See http://goo.gl/
- expecting a function but got %s
AI-assisted analysis of petkaantonov/bluebird@c220cfe480 (2026-09-02).
Data as JSON: /api/errors/867c7dffe741d46b.
Report an issue: GitHub.