{"record":{"id":"b697aba6f12131f0","repo":"medusajs/medusa","slug":"primary-keys-are-not-defined-by-the-module-keyna","errorCode":null,"errorMessage":"Primary keys are not defined by the module ${keyName}. Setting default primary key to 'id'","messagePattern":"Primary keys are not defined by the module (.+?)\\. Setting default primary key to 'id'","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/modules-sdk/src/medusa-module.ts","lineNumber":684,"sourceCode":"\n        try {\n          // TODO: rework that to store on a separate property\n          joinerConfig =\n            typeof services[keyName].__joinerConfig === \"function\"\n              ? await services[keyName].__joinerConfig?.()\n              : services[keyName].__joinerConfig\n        } catch {\n          // noop\n        }\n\n        if (!joinerConfig) {\n          throw new Error(\n            `Your module is missing a joiner config: ${keyName}. If this module is not queryable, please set { definition: { isQueryable: false } } in your module configuration.`\n          )\n        }\n\n        if (!joinerConfig.primaryKeys) {\n          logger_.warn(\n            `Primary keys are not defined by the module ${keyName}. Setting default primary key to 'id'${EOL}`\n          )\n\n          joinerConfig.primaryKeys = [\"id\"]\n        }\n\n        joinerConfig = {\n          ...joinerConfig,\n          databaseClientUrl: resolveJoinerConfigDatabaseClientUrl(resolution),\n        }\n\n        services[keyName].__joinerConfig = joinerConfig\n        MedusaModule.setJoinerConfig(keyName, joinerConfig)\n      }\n\n      MedusaModule.setModuleResolution(keyName, resolution)\n\n      MedusaModule.registerModule(keyName, {","sourceCodeStart":666,"sourceCodeEnd":702,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/core/modules-sdk/src/medusa-module.ts#L666-L702","documentation":"When Medusa registers a loaded module in medusa-module.ts, it reads the module's joinerConfig() to learn its primary keys for the Query/remote joiner. If primaryKeys is missing or empty, it warns and falls back to ['id']. Queries will work only if the underlying data model actually has an `id` column as its key.","triggerScenarios":"A custom module whose defineJoinerConfig (or joinerConfig return) omits `primaryKeys`, or returns it as an empty array, while its service is registered as queryable.","commonSituations":"Writing a first custom module and copying a joiner config template without filling in primaryKeys; modules keyed on a differently named column (e.g. code) — queries then filter on a non-existent id and return nothing or throw SQL errors.","solutions":["Add primaryKeys to the module's joiner config: return { ...defineJoinerConfig(...), primaryKeys: [\"id\"] } matching the data model's actual key column","If the key column is not `id`, list it explicitly (e.g. primaryKeys: [\"code\"]) so remote-query filters hit the right column","If the module should not be queryable at all, set definition: { isQueryable: false } in its module declaration"],"exampleFix":"// before\nexport const joinerConfig = defineJoinerConfig(MODULE_MODEL)\n// no primaryKeys -> defaults to id\n\n// after\nexport const joinerConfig = defineJoinerConfig(MODULE_MODEL, {\n  primaryKeys: [\"id\"],\n})","handlingStrategy":"validation","validationCode":"const joiner = module.joinerConfig()\nif (!joiner.primaryKeys?.length) {\n  throw new Error(`${keyName} joiner config missing primaryKeys`)\n}","typeGuard":"const hasPrimaryKeys = (c: any): c is { primaryKeys: string[] } =>\n  Array.isArray(c?.primaryKeys) && c.primaryKeys.length > 0","tryCatchPattern":null,"preventionTips":["Always set primaryKeys in defineJoinerConfig for custom modules","Set isQueryable:false for non-queryable modules","Add a unit test asserting joinerConfig().primaryKeys matches the model keys"],"tags":["modules-sdk","joiner-config","query","primary-key"],"backgroundTag":"missing-required-config","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}