{"record":{"id":"cecbf3a1aa1f4fc6","repo":"microsoft/playwright","slug":"cannot-uncheck-radio-button-radio-buttons-can-onl","errorCode":null,"errorMessage":"Cannot uncheck radio button. Radio buttons can only be unchecked by selecting another radio button in the same group.","messagePattern":"Cannot uncheck radio button\\. Radio buttons can only be unchecked by selecting another radio button in the same group\\.","errorType":"exception","errorClass":"NonRecoverableDOMError","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/dom.ts","lineNumber":836,"sourceCode":"\n  async uncheck(progress: Progress, options: { position?: types.Point } & types.PointerActionWaitOptions) {\n    const result = await this._setChecked(progress, false, options);\n    return assertDone(throwRetargetableDOMError(result));\n  }\n\n  async _setChecked(progress: Progress, state: boolean, options: { position?: types.Point } & types.PointerActionWaitOptions): Promise<'error:notconnected' | 'done'> {\n    const isChecked = async (progress: Progress) => {\n      const result = await progress.race(this.evaluateInUtility(([injected, node]) => injected.elementState(node, 'checked'), {}));\n      if (result === 'error:notconnected' || result.received === 'error:notconnected')\n        throwElementIsNotAttached();\n      return { matches: result.matches, isRadio: result.isRadio };\n    };\n    await this._markAsTargetElement(progress);\n    const checkedState = await isChecked(progress);\n    if (checkedState.matches === state)\n      return 'done';\n    if (!state && checkedState.isRadio)\n      throw new NonRecoverableDOMError('Cannot uncheck radio button. Radio buttons can only be unchecked by selecting another radio button in the same group.');\n    const result = await this._click(progress, { ...options, waitAfter: 'disabled' });\n    if (result !== 'done')\n      return result;\n    if (options.trial)\n      return 'done';\n    const finalState = await isChecked(progress);\n    if (finalState.matches !== state)\n      throw new NonRecoverableDOMError('Clicking the checkbox did not change its state');\n    return 'done';\n  }\n\n  async boundingBox(progress: Progress): Promise<types.Rect | null> {\n    return await progress.race(this._page.delegate.getBoundingBox(this));\n  }\n\n  async screenshot(progress: Progress, options: ScreenshotOptions): Promise<Buffer> {\n    return await this._page.screenshotter.screenshotElement(progress, this, options);\n  }","sourceCodeStart":818,"sourceCodeEnd":854,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/dom.ts#L818-L854","documentation":"Radio buttons (input[type=radio]) can only be turned on, never off — unchecked by selecting a sibling radio in the same name group. _setChecked throws NonRecoverableDOMError when asked to set state=false and the element is a radio (isRadio:true), because toggling a radio to false is not a valid DOM operation.","triggerScenarios":"Calling locator.uncheck() (or setChecked(false)) on an input[type=radio]; generic form-reset code that unchecks every checkbox and radio in a group.","commonSituations":"Looping over all toggleable inputs and calling uncheck on each; treating radios like checkboxes in shared helper code; trying to clear a form by unchecking radios.","solutions":["Do not uncheck radios; to deselect, check a different radio in the same name group (or a dedicated 'none' option).","Detect the input type before calling uncheck and skip radios.","Reset the radio group by selecting another option rather than unchecking the current one."],"exampleFix":"// before\nawait page.locator('input[name=opt]').uncheck(); // radio → throws\n// after — select a different radio to change selection\nawait page.locator('input[name=opt][value=none]').check();","handlingStrategy":"type-guard","validationCode":"// Skip radios when unchecking a group of toggles.\nconst type = await locator.getAttribute('type');\nif (type !== 'radio') await locator.uncheck();","typeGuard":"// Treat radios as non-uncheckable.\nasync function isRadio(locator: Locator): Promise<boolean> {\n  return (await locator.getAttribute('type')) === 'radio';\n}","tryCatchPattern":null,"preventionTips":["Never call uncheck() on input[type=radio].","Detect the input type before generic uncheck loops.","To change a radio selection, check a different option in the group."],"tags":["form","radio","checkbox","api-misuse"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}