medusajs/medusa · critical · Error

Module ${moduleConfig.resolve} doesn't have a serviceName. P

Error message

Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.

What it means

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.

Source

Thrown at packages/core/utils/src/common/define-config.ts:162

       * resolved from the project directory. Otherwise the lookup starts in
       * whichever "node_modules" directory `@medusajs/utils` was hoisted into,
       * which in a workspace monorepo does not contain the plugin.
       */
      const moduleExport = isString(resolution)
        ? require(resolveFromProject(resolution, projectDir))
        : resolution

      const defaultExport = resolveExports(moduleExport).default

      const joinerConfig =
        typeof defaultExport.service.prototype.__joinerConfig === "function"
          ? defaultExport.service.prototype.__joinerConfig() ?? {}
          : defaultExport.service.prototype.__joinerConfig ?? {}

      serviceName = joinerConfig.serviceName

      if (!serviceName) {
        throw new Error(
          `Module ${moduleConfig.resolve} doesn't have a serviceName. Please provide a 'key' for the module or check the service joiner config.`
        )
      }
    }

    acc[serviceName] = moduleConfig

    return acc
  }, {})

  return remappedModules as Exclude<ConfigModule["modules"], undefined>
}

function getKnownModuleName(
  moduleConfig: InputConfigModules[number]
): string | undefined {
  if ("key" in moduleConfig && moduleConfig.key) {
    return moduleConfig.key

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Set an explicit `key` on the module declaration: `{ resolve: "./src/modules/my-module", key: "myModule" }`
  2. Ensure the module's service extends `MedusaService(...)` and its model/service defines a serviceName (check `__joinerConfig()` on the service prototype)
  3. Verify the resolve path points to the module entry exporting `service` correctly
  4. If using a third-party module, update it to a version compatible with your @medusajs/* packages

Example fix

// medusa-config.js before
modules: [{ resolve: "./src/modules/blog" }]
// after
modules: [{ resolve: "./src/modules/blog", key: "blog" }]
Defensive patterns

Strategy: validation

Validate before calling

// before loading config
const svc = (await import(modulePath)).default?.service
const name = svc?.prototype?.__joinerConfig?.()?.serviceName
if (!name && !decl.key) throw new Error(`module ${modulePath} needs a key`)

Type guard

const hasServiceName = (d: any): boolean => Boolean(d?.key || d?.service?.prototype?.__joinerConfig?.()?.serviceName)

Try / catch

try { defineConfig(config) } catch (e) { if (/doesn't have a serviceName/.test(e.message)) add explicit `key` to the module declaration; else throw e }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/589e6787308bf840. Report an issue: GitHub.