{"record":{"id":"589e6787308bf840","repo":"medusajs/medusa","slug":"module-moduleconfig-resolve-doesn-t-have-a-serv","errorCode":null,"errorMessage":"Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.","messagePattern":"Module (.+?) doesn't have a serviceName\\. Please provide a 'key' for the module or check the service joiner config\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/core/utils/src/common/define-config.ts","lineNumber":162,"sourceCode":"       * resolved from the project directory. Otherwise the lookup starts in\n       * whichever \"node_modules\" directory `@medusajs/utils` was hoisted into,\n       * which in a workspace monorepo does not contain the plugin.\n       */\n      const moduleExport = isString(resolution)\n        ? require(resolveFromProject(resolution, projectDir))\n        : resolution\n\n      const defaultExport = resolveExports(moduleExport).default\n\n      const joinerConfig =\n        typeof defaultExport.service.prototype.__joinerConfig === \"function\"\n          ? defaultExport.service.prototype.__joinerConfig() ?? {}\n          : defaultExport.service.prototype.__joinerConfig ?? {}\n\n      serviceName = joinerConfig.serviceName\n\n      if (!serviceName) {\n        throw new Error(\n          `Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.`\n        )\n      }\n    }\n\n    acc[serviceName] = moduleConfig\n\n    return acc\n  }, {})\n\n  return remappedModules as Exclude<ConfigModule[\"modules\"], undefined>\n}\n\nfunction getKnownModuleName(\n  moduleConfig: InputConfigModules[number]\n): string | undefined {\n  if (\"key\" in moduleConfig && moduleConfig.key) {\n    return moduleConfig.key","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/core/utils/src/common/define-config.ts#L144-L180","documentation":"Thrown while Medusa loads its module declarations during config resolution. When a module is declared only by a `resolve` path (no explicit `key`/serviceName), Medusa loads the module's service and reads its `__joinerConfig().serviceName`. If that is missing, the module cannot be registered under a canonical name and startup aborts.","triggerScenarios":"Declaring a custom or local module in medusa-config.js with only `resolve: \"./src/modules/my-module\"` (or a package path) where the module's service definition lacks a `serviceName` in its `MedusaService`/joiner config; also when a third-party plugin module's version changed its joiner config.","commonSituations":"Custom module whose service was created without extending MedusaService correctly, a typo'd resolve path loading the wrong default export, or upgrading a module package whose joiner config shape changed.","solutions":["Set an explicit `key` on the module declaration: `{ resolve: \"./src/modules/my-module\", key: \"myModule\" }`","Ensure the module's service extends `MedusaService(...)` and its model/service defines a serviceName (check `__joinerConfig()` on the service prototype)","Verify the resolve path points to the module entry exporting `service` correctly","If using a third-party module, update it to a version compatible with your @medusajs/* packages"],"exampleFix":"// medusa-config.js before\nmodules: [{ resolve: \"./src/modules/blog\" }]\n// after\nmodules: [{ resolve: \"./src/modules/blog\", key: \"blog\" }]","handlingStrategy":"validation","validationCode":"// before loading config\nconst svc = (await import(modulePath)).default?.service\nconst name = svc?.prototype?.__joinerConfig?.()?.serviceName\nif (!name && !decl.key) throw new Error(`module ${modulePath} needs a key`)","typeGuard":"const hasServiceName = (d: any): boolean => Boolean(d?.key || d?.service?.prototype?.__joinerConfig?.()?.serviceName)","tryCatchPattern":"try { defineConfig(config) } catch (e) { if (/doesn't have a serviceName/.test(e.message)) add explicit `key` to the module declaration; else throw e }","preventionTips":["Always set an explicit `key` for custom modules","Write a smoke test that calls defineConfig() on your medusa-config in CI"],"tags":["modules","config","startup","medusa-config"],"backgroundTag":"module-resolution-failed","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}