{"record":{"id":"f7a238e124e0e162","repo":"payloadcms/payload","slug":"operator-handler-handler-name-cannot-define-b","errorCode":null,"errorMessage":"Operator handler \"${handler.name}\" cannot define both \"build\" and \"transformOperands\". Use \"transformOperands\" to adjust operands, or \"build\" to replace the comparison entirely.","messagePattern":"Operator handler \"(.+?)\" cannot define both \"build\" and \"transformOperands\"\\. Use \"transformOperands\" to adjust operands, or \"build\" to replace the comparison entirely\\.","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"critical","filePath":"packages/drizzle/src/queries/validateOperatorHandlers.ts","lineNumber":25,"sourceCode":"): handler is DrizzleOperatorReplacementHandler => typeof handler.build === 'function'\n\nconst fieldTypesOverlap = (\n  a: DrizzleOperatorReplacementHandler,\n  b: DrizzleOperatorReplacementHandler,\n): boolean =>\n  !a.fieldTypes ||\n  !b.fieldTypes ||\n  a.fieldTypes.some((fieldType) => b.fieldTypes.includes(fieldType))\n\n/**\n * Validates operator-handler configuration before any request runs: rejects a handler that\n * defines both `build` and `transformOperands`, and rejects two replacement handlers whose\n * `operators` and `fieldTypes` both overlap for the same resolved operator.\n */\nexport const validateOperatorHandlers = (operatorHandlers: DrizzleOperatorHandler[]): void => {\n  for (const handler of operatorHandlers) {\n    if (typeof handler.build === 'function' && typeof handler.transformOperands === 'function') {\n      throw new APIError(\n        `Operator handler \"${handler.name}\" cannot define both \"build\" and \"transformOperands\". Use \"transformOperands\" to adjust operands, or \"build\" to replace the comparison entirely.`,\n      )\n    }\n  }\n\n  const replacementHandlers = operatorHandlers.filter(isReplacementHandler)\n\n  for (let i = 0; i < replacementHandlers.length; i++) {\n    for (let j = i + 1; j < replacementHandlers.length; j++) {\n      const handlerA = replacementHandlers[i]\n      const handlerB = replacementHandlers[j]\n\n      const sharedOperators = handlerA.operators.filter((operator) =>\n        handlerB.operators.includes(operator),\n      )\n\n      if (!sharedOperators.length) {\n        continue","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/drizzle/src/queries/validateOperatorHandlers.ts#L7-L43","documentation":"Thrown at adapter boot by validateOperatorHandlers when a custom DrizzleOperatorHandler defines both a 'build' and a 'transformOperands' function. These two are mutually exclusive: 'transformOperands' adjusts the operands before the default comparison runs, while 'build' replaces the comparison entirely. Allowing both would make execution order ambiguous, so the config is rejected before any request is served.","triggerScenarios":"Registering a custom operator handler (via operatorHandlers on the Drizzle adapter) whose object literal includes both `build` and `transformOperands` keys as functions.","commonSituations":"Copying a handler as a starting point and adding the other key without removing the original; upgrading the adapter across a version that introduced transformOperands and not pruning the old build fn.","solutions":["Decide whether you want to adjust operands (keep transformOperands, drop build) or fully replace the SQL (keep build, drop transformOperands).","Run the adapter's operator-handler validation in a unit test (validateOperatorHandlers.spec.ts pattern) so misconfiguration fails at test time, not boot.","Check the DrizzleOperatorHandler type definition to confirm only one of the two keys is allowed for your use case."],"exampleFix":"// before\nconst handler = {\n  name: 'my-like',\n  operators: ['like'],\n  build: (opts) => sql`...`,\n  transformOperands: (operands) => operands.map(...),\n}\n// after\nconst handler = {\n  name: 'my-like',\n  operators: ['like'],\n  transformOperands: (operands) => operands.map(...),\n}","handlingStrategy":"validation","validationCode":"function assertHandlerConfig(handler) {\n  if (typeof handler.build === 'function' && typeof handler.transformOperands === 'function') {\n    throw new Error(`Handler ${handler.name} must not define both build and transformOperands`)\n  }\n}","typeGuard":"const hasBuildAndTransform = (h) => typeof h.build === 'function' && typeof h.transformOperands === 'function'","tryCatchPattern":null,"preventionTips":["Run validateOperatorHandlers in a unit test for your operatorHandlers array before wiring the adapter.","Treat the DrizzleOperatorHandler type as authoritative: never include both keys."],"tags":["operator-handlers","configuration","boot","validation"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}