{"record":{"id":"867c7dffe741d46b","repo":"petkaantonov/bluebird","slug":"cannot-promisify-an-api-that-has-normal-methods-wi","errorCode":null,"errorMessage":"Cannot promisify an API that has normal methods with '%s'-suffix\n\n    See http://goo.gl/MqrFmX\n","messagePattern":"Cannot promisify an API that has normal methods with '(.+?)'-suffix\n\n    See http://goo\\.gl/MqrFmX\n","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/promisify.js","lineNumber":59,"sourceCode":"    }\n}\n\nfunction hasPromisified(obj, key, suffix) {\n    var val = util.getDataPropertyOrDefault(obj, key + suffix,\n                                            defaultPromisified);\n    return val ? isPromisified(val) : false;\n}\nfunction checkValid(ret, suffix, suffixRegexp) {\n    // Verify that in the list of methods to promisify there is no\n    // method that has a name ending in \"Async\"-suffix while\n    // also having a method with the same name but no Async suffix\n    for (var i = 0; i < ret.length; i += 2) {\n        var key = ret[i];\n        if (suffixRegexp.test(key)) {\n            var keyWithoutAsyncSuffix = key.replace(suffixRegexp, \"\");\n            for (var j = 0; j < ret.length; j += 2) {\n                if (ret[j] === keyWithoutAsyncSuffix) {\n                    throw new TypeError(PROMISIFICATION_NORMAL_METHODS_ERROR\n                        .replace(\"%s\", suffix));\n                }\n            }\n        }\n    }\n}\n\nfunction promisifiableMethods(obj, suffix, suffixRegexp, filter) {\n    var keys = util.inheritedDataKeys(obj);\n    var ret = [];\n    for (var i = 0; i < keys.length; ++i) {\n        var key = keys[i];\n        var value = obj[key];\n        var passesDefaultFilter = filter === defaultFilter\n            ? true : defaultFilter(key, value, obj);\n        if (typeof value === \"function\" &&\n            !isPromisified(value) &&\n            !hasPromisified(obj, key, suffix) &&","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/petkaantonov/bluebird/blob/c220cfe480868e2f5c5de4fe8bb3b04b97588d7f/src/promisify.js#L41-L77","documentation":"`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.","triggerScenarios":"`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`).","commonSituations":"Promisifying libraries that already ship async-suffixed methods (some fs wrappers, AWS clients); switching suffixes without checking existing method names.","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`."],"exampleFix":"// before\nPromise.promisifyAll(fs); // fs has read and readAsync\n// after\nPromise.promisifyAll(fs, { suffix: 'Promised' });","handlingStrategy":"validation","validationCode":"const keys = Object.keys(target).filter(k => typeof target[k] === 'function');\nconst suffixed = keys.filter(k => k.endsWith('Async')).map(k => k.slice(0, -'Async'.length));\nif (suffixed.some(base => keys.includes(base))) {\n  throw new Error('promisifyAll suffix conflict detected');\n}\nPromise.promisifyAll(target, { suffix: 'Async' });","typeGuard":null,"tryCatchPattern":"try {\n  Promise.promisifyAll(target);\n} catch (e) {\n  if (String(e).includes('normal methods')) {\n    target = Promise.promisifyAll(target, { suffix: 'Promised' });\n  } else throw e;\n}","preventionTips":["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."],"tags":["typeerror","promisify","naming-conflict"],"backgroundTag":"promisifyall-suffix-conflict","analyzedSha":"c220cfe480868e2f5c5de4fe8bb3b04b97588d7f","analyzedAt":"2026-09-02T02:30:20.863Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}