{"record":{"id":"3047bb37f42f1ed8","repo":"YMFE/yapi","slug":"singlehook-name","errorCode":null,"errorMessage":"重复绑定singleHook(${name}), 请检查","messagePattern":"重复绑定singleHook\\((.+?)\\), 请检查","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/plugin.js","lineNumber":203,"sourceCode":"   *    hander: (emails, title, content)=> {...}\n   * }\n   */\n  addNotice:{\n    type: 'multi',\n    listener: []\n  }\n};\n\nfunction bindHook(name, listener) {\n  if (!name) throw new Error('缺少hookname');\n  if (name in hooks === false) {\n    throw new Error('不存在的hookname');\n  }\n  if (hooks[name].type === 'multi') {\n    hooks[name].listener.push(listener);\n  } else {\n    if (typeof hooks[name].listener === 'function') {\n      throw new Error('重复绑定singleHook(' + name + '), 请检查');\n    }\n    hooks[name].listener = listener;\n  }\n}\n\n/**\n *\n * @param {*} hookname\n * @return promise\n */\nfunction emitHook(name) {\n  if (hooks[name] && typeof hooks[name] === 'object') {\n    let args = Array.prototype.slice.call(arguments, 1);\n    if (hooks[name].type === 'single' && typeof hooks[name].listener === 'function') {\n      return Promise.resolve(hooks[name].listener.apply(yapi, args));\n    }\n    let promiseAll = [];\n    if (Array.isArray(hooks[name].listener)) {","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/YMFE/yapi/blob/59bade3a8a43e7db077d38a4b0c7c584f30ddf8c/server/plugin.js#L185-L221","documentation":"For 'single' type hooks only one listener is allowed; binding a second listener to the same single hook throws this error. Multi hooks accept an array of listeners, single hooks hold exactly one function.","triggerScenarios":"bindHook called twice with the same single-hook name, e.g. two plugins (or the same plugin loaded twice) both bindHook('init', fn).","commonSituations":"Duplicate plugin entries in config.json, plugin module accidentally required/loaded twice, two plugins targeting the same single hook point.","solutions":["Remove the duplicate bindHook call or guard it with a check before binding.","Ensure the plugin is listed only once in config.json plugins array.","If both bindings are needed, check whether the hook is defined as 'multi' type, or merge logic into one listener."],"exampleFix":"// before\nyapi.bindHook('init', initA);\nyapi.bindHook('init', initB); // throws\n// after\nyapi.bindHook('init', () => { initA(); initB(); });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  yapi.bindHook('init', listener);\n} catch (e) {\n  if (e.message.startsWith('重复绑定singleHook')) {\n    console.warn('Hook already bound, skipping duplicate bind');\n  } else { throw e; }\n}","preventionTips":["Track bound hooks in your plugin with a Set and skip re-binding.","List each plugin only once in config.json.","Merge multiple init actions into a single listener for single hooks."],"tags":["plugin","hooks","duplicate-registration"],"backgroundTag":"duplicate-registration","analyzedSha":"59bade3a8a43e7db077d38a4b0c7c584f30ddf8c","analyzedAt":"2026-08-29T08:45:22.203Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}