{"record":{"id":"7deb37f0046a2462","repo":"payloadcms/payload","slug":"operator-handlers-handlera-name-and-handle","errorCode":null,"errorMessage":"Operator handlers \"${handlerA.name}\" and \"${handlerB.name}\" both replace the \"${sharedOperators.join('\", \"')}\" operator for overlapping field types. Only one replacement handler may match a given resolved operator and field type.","messagePattern":"Operator handlers \"(.+?)\" and \"(.+?)\" both replace the \"(.+?)\" operator for overlapping field types\\. Only one replacement handler may match a given resolved operator and field type\\.","errorType":"http","errorClass":"APIError","httpStatus":500,"severity":"critical","filePath":"packages/drizzle/src/queries/validateOperatorHandlers.ts","lineNumber":47,"sourceCode":"  }\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\n      }\n\n      if (fieldTypesOverlap(handlerA, handlerB)) {\n        throw new APIError(\n          `Operator handlers \"${handlerA.name}\" and \"${handlerB.name}\" both replace the \"${sharedOperators.join('\", \"')}\" operator for overlapping field types. Only one replacement handler may match a given resolved operator and field type.`,\n        )\n      }\n    }\n  }\n}\n","sourceCodeStart":29,"sourceCodeEnd":54,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/drizzle/src/queries/validateOperatorHandlers.ts#L29-L54","documentation":"Thrown at adapter boot when two replacement operator handlers (handlers with a 'build' function) both declare the same operator AND their fieldTypes overlap. Because a replacement handler fully replaces the comparison, two of them matching the same resolved (operator, fieldType) would be non-deterministic, so the adapter refuses to start. Note fieldTypesOverlap treats undefined fieldTypes as 'matches everything'.","triggerScenarios":"Registering two operatorHandlers that both list (for example) 'like' in their `operators` array, where both omit fieldTypes or both include a common fieldType such as 'text'.","commonSituations":"Adding a plugin that contributes its own operator handlers that collide with handlers you already registered; forking a handler and forgetting to narrow its fieldTypes or rename its operator.","solutions":["Give each replacement handler a disjoint set of operators, or disjoint fieldTypes arrays, so at most one matches any resolved operator+fieldType.","If both handlers legitimately target the same operator/fieldType, merge them into a single handler whose build branches on the field.","Drop one of the conflicting handlers if it is redundant."],"exampleFix":"// before\nconst a = { name: 'a', operators: ['like'], fieldTypes: ['text'], build: ... }\nconst b = { name: 'b', operators: ['like'], fieldTypes: ['text'], build: ... }\n// after\nconst b = { name: 'b', operators: ['like'], fieldTypes: ['textarea'], build: ... }","handlingStrategy":"validation","validationCode":"function assertNoReplacementOverlap(handlers) {\n  const reps = handlers.filter(h => typeof h.build === 'function')\n  for (let i = 0; i < reps.length; i++) {\n    for (let j = i + 1; j < reps.length; j++) {\n      const a = reps[i], b = reps[j]\n      const sharedOps = a.operators.filter(o => b.operators.includes(o))\n      const typesOverlap = !a.fieldTypes || !b.fieldTypes || a.fieldTypes.some(t => b.fieldTypes.includes(t))\n      if (sharedOps.length && typesOverlap) {\n        throw new Error(`${a.name} and ${b.name} overlap on ${sharedOps}`)\n      }\n    }\n  }\n}","typeGuard":"const isReplacement = (h) => typeof h.build === 'function'","tryCatchPattern":null,"preventionTips":["Always set a narrow fieldTypes array on replacement handlers instead of leaving it undefined.","Keep all operator handlers in one module so overlaps are visually obvious."],"tags":["operator-handlers","configuration","boot","validation"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}