{"record":{"id":"87bd5a5e90922c2f","repo":"homebridge/homebridge","slug":"plugin-this-pluginpath-does-not-export-an-initi","errorCode":null,"errorMessage":"Plugin ${this.pluginPath} does not export an initializer function from ${this.main}. Found default export of type '${typeof pluginModules}'${defaultKeysStr}${exportedKeysStr}. The plugin must default-export a function that takes the homebridge api object.","messagePattern":"Plugin (.+?) does not export an initializer function from (.+?)\\. Found default export of type '(.+?)'(.+?)(.+?)\\. The plugin must default-export a function that takes the homebridge api object\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/plugin.ts","lineNumber":237,"sourceCode":"    const pluginModules = pluginModule.default\n\n    if (typeof pluginModules === 'function') {\n      this.pluginInitializer = pluginModules\n    } else if (pluginModules && typeof pluginModules.default === 'function') {\n      this.pluginInitializer = pluginModules.default\n    } else {\n      // Be specific about what we found instead of just \"doesn't export an\n      // initializer\". Helps plugin authors and users diagnose ESM/CJS\n      // shape mismatches at a glance.\n      const exportedKeys = pluginModule && typeof pluginModule === 'object'\n        ? Object.keys(pluginModule).filter(k => k !== 'default').slice(0, 10)\n        : []\n      const defaultKeys = pluginModules && typeof pluginModules === 'object'\n        ? Object.keys(pluginModules).slice(0, 10)\n        : []\n      const defaultKeysStr = defaultKeys.length > 0 ? ` with keys [${defaultKeys.join(', ')}]` : ''\n      const exportedKeysStr = exportedKeys.length > 0 ? `; named exports: [${exportedKeys.join(', ')}]` : ''\n      throw new Error(\n        `Plugin ${this.pluginPath} does not export an initializer function from ${this.main}. Found default export of type '${typeof pluginModules}'${defaultKeysStr}${exportedKeysStr}. The plugin must default-export a function that takes the homebridge api object.`,\n      )\n    }\n  }\n\n  public initialize(api: API): void | Promise<void> {\n    if (!this.pluginInitializer) {\n      throw new Error('Tried to initialize a plugin which hasn\\'t been loaded yet!')\n    }\n\n    return this.pluginInitializer(api)\n  }\n}\n","sourceCodeStart":219,"sourceCodeEnd":251,"githubUrl":"https://github.com/homebridge/homebridge/blob/edf54930340d67cade23d01abd41b03cd9621e8b/src/plugin.ts#L219-L251","documentation":"Homebridge expects every plugin's module entry point (package.json 'main') to default-export an initializer function `(api: HomebridgeAPI) => void`. If the default export is not a function (object, class instance, undefined, etc.), Plugin.load() throws with the detected export type plus its keys to help identify the mistake.","triggerScenarios":"After dynamic import of this.main, `typeof pluginModules.default !== 'function'`. Includes undefined default export, an exported object literal, a class (non-callable-as-initializer shape), or everything exported only via named exports.","commonSituations":"TypeScript/ESM plugins written with `export default { ... }` or only `export class MyPlugin`; CommonJS plugins assigning `module.exports = { initialize }` without a default; bundlers (esbuild/rollup) misconfigured with wrong output format so the default export lands in a namespace object; converting a plugin from CommonJS to ESM and dropping `export default`.","solutions":["Make the entry point default-export a function that receives the API: `export default (api: API) => { ... }`.","If the plugin uses a class, export a factory: `export default (api) => new MyPlugin(api)` or keep `export default MyPlugin` only if it matches the expected initializer shape.","Check package.json 'main' points at the compiled file that actually contains the default export (e.g. dist/index.js, not src/index.ts).","Inspect the named-exports list in the message; if your initializer is a named export like `initialize`, re-export it as default: `export { initialize as default }`.","Rebuild the plugin and confirm the bundler emits a true default export (`node -e \"import('...').then(m=>console.log(typeof m.default))\"`)."],"exampleFix":"// before: index.ts\nclass MyPlatform { constructor(log, config) {} }\nexport { MyPlatform }\n// after\nclass MyPlatform { constructor(log, config) {} }\nexport default (api: API) => {\n  api.registerPlatform('MyPlatform', MyPlatform)\n}","handlingStrategy":"validation","validationCode":"const mod = await import(pluginMain)\nif (typeof mod.default !== 'function') {\n  throw new Error(`Plugin entry must default-export a function; got ${typeof mod.default}`)\n}","typeGuard":"function isPluginInitializer(m: unknown): m is (api: unknown) => void | Promise<void> {\n  return typeof m === 'function'\n}","tryCatchPattern":"try {\n  await plugin.initialize(api)\n} catch (e) {\n  log.error(`Plugin failed to load: ${(e as Error).message}`)\n}","preventionTips":["Scaffold plugins from homebridge-plugin-template which has the correct export shape.","Set package.json 'main' to the compiled dist file, never a .ts source.","Smoke-test with `node -e \"import('./dist/index.js').then(m=>console.log(typeof m.default))\"`.","Avoid `export default { ... }` namespace objects; default-export a function."],"tags":["plugin","esm","module-exports","typescript"],"backgroundTag":"missing-plugin-initializer","analyzedSha":"edf54930340d67cade23d01abd41b03cd9621e8b","analyzedAt":"2026-08-30T21:28:53.235Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}