{"record":{"id":"3fb91688761b066b","repo":"puppeteer/puppeteer","slug":"at-least-one-query-method-must-be-defined","errorCode":null,"errorMessage":"At least one query method must be defined.","messagePattern":"At least one query method must be defined\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/puppeteer-core/src/injected/CustomQuerySelector.ts","lineNumber":41,"sourceCode":"  #selectors = new Map<string, CustomQuerySelector>();\n\n  register(name: string, handler: CustomQueryHandler): void {\n    if (!handler.queryOne && handler.queryAll) {\n      const querySelectorAll = handler.queryAll;\n      handler.queryOne = (node, selector) => {\n        for (const result of querySelectorAll(node, selector)) {\n          return result;\n        }\n        return null;\n      };\n    } else if (handler.queryOne && !handler.queryAll) {\n      const querySelector = handler.queryOne;\n      handler.queryAll = (node, selector) => {\n        const result = querySelector(node, selector);\n        return result ? [result] : [];\n      };\n    } else if (!handler.queryOne || !handler.queryAll) {\n      throw new Error('At least one query method must be defined.');\n    }\n\n    this.#selectors.set(name, {\n      querySelector: handler.queryOne,\n      querySelectorAll: handler.queryAll!,\n    });\n  }\n\n  unregister(name: string): void {\n    this.#selectors.delete(name);\n  }\n\n  get(name: string): CustomQuerySelector | undefined {\n    return this.#selectors.get(name);\n  }\n\n  clear(): void {\n    this.#selectors.clear();","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/puppeteer/puppeteer/blob/d484e21c17f6023826fefdcdeeb553e04a7aaed8/packages/puppeteer-core/src/injected/CustomQuerySelector.ts#L23-L59","documentation":"CustomQuerySelectorRegistry.register requires a handler that defines at least one of queryOne or queryAll (it can derive the other). The final else-if catches the case where BOTH are missing/undefined and rejects the registration. This guards Puppeteer.registerCustomQueryHandler against useless handlers.","triggerScenarios":"Calling Puppeteer.registerCustomQueryHandler('name', {}) with an empty handler object, or with a handler whose queryOne and queryAll are both undefined (e.g. a typo in the method name).","commonSituations":"Typos like { queyOne: ... } (misspelled); passing a class instance that doesn't expose the expected methods; spreading a config that omits both keys.","solutions":["Provide at least queryOne or queryAll in the handler passed to registerCustomQueryHandler.","Double-check method names are exactly 'queryOne' and 'queryAll'.","If you only have a multi-result query, register queryAll and Puppeteer will synthesize queryOne (and vice-versa).","Add a compile-time type annotation (: CustomQueryHandler) to catch missing methods at build time."],"exampleFix":"// before\nPuppeteer.registerCustomQueryHandler('foo', {});\n\n// after\nPuppeteer.registerCustomQueryHandler('foo', {\n  queryAll: (node, selector) => node.querySelectorAll(selector),\n});","handlingStrategy":"validation","validationCode":"function registerSafe(name: string, handler: Record<string, unknown>) {\n  if (typeof handler.queryOne !== 'function' && typeof handler.queryAll !== 'function') {\n    throw new Error(`Cannot register '${name}': provide queryOne and/or queryAll`);\n  }\n  Puppeteer.registerCustomQueryHandler(name, handler as any);\n}","typeGuard":"const isValidHandler = (h: unknown): boolean =>\n  !!h && (typeof (h as any).queryOne === 'function' ||\n          typeof (h as any).queryAll === 'function');","tryCatchPattern":"try {\n  Puppeteer.registerCustomQueryHandler('name', handler);\n} catch (e) {\n  if (e instanceof Error && e.message === 'At least one query method must be defined.') {\n    // handler missing methods — log and skip registration\n  }\n  throw e;\n}","preventionTips":["Annotate handlers with the CustomQueryHandler type to catch missing methods at build time.","Double-check method names are exactly queryOne/queryAll.","Register only one of the two if you have a single-result or multi-result implementation."],"tags":["selectors","custom-query-handler","validation"],"backgroundTag":null,"analyzedSha":"d484e21c17f6023826fefdcdeeb553e04a7aaed8","analyzedAt":"2026-08-12T06:33:19.665Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}