{"record":{"id":"172263e472cdb5c6","repo":"alibaba/page-agent","slug":"element-is-not-an-input-textarea-or-contentedita","errorCode":null,"errorMessage":"Element is not an input, textarea, or contenteditable","messagePattern":"Element is not an input, textarea, or contenteditable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/page-controller/src/actions.ts","lineNumber":134,"sourceCode":"\n\t// Release\n\ttarget.dispatchEvent(new PointerEvent('pointerup', pointerOpts))\n\ttarget.dispatchEvent(new MouseEvent('mouseup', mouseOpts))\n\n\t// Click — activation behavior (navigation, form submit, etc.) triggers\n\t// via bubbling from target up to the interactive ancestor.\n\ttarget.click()\n\n\tawait waitFor(0.2)\n}\n\n/**\n * @private Internal method, subject to change at any time.\n */\nexport async function inputTextElement(element: HTMLElement, text: string) {\n\tconst isContentEditable = element.isContentEditable\n\tif (!isInputElement(element) && !isTextAreaElement(element) && !isContentEditable) {\n\t\tthrow new Error('Element is not an input, textarea, or contenteditable')\n\t}\n\n\tawait clickElement(element)\n\n\tif (isContentEditable) {\n\t\t// Contenteditable support (partial)\n\t\t// Not supported:\n\t\t// - Monaco/CodeMirror: Require direct JS instance access. No universal way to obtain.\n\t\t// - Draft.js: Not responsive to synthetic/execCommand/Range/DataTransfer. Unmaintained.\n\t\t//\n\t\t// Strategy: Try Plan A (synthetic events) first, then verify and fall back\n\t\t// to Plan B (execCommand) if the text wasn't actually inserted.\n\t\t//\n\t\t// Plan A: Dispatch synthetic events\n\t\t// Works: React contenteditable, Quill.\n\t\t// Fails: Slate.js, some contenteditable editors that ignore synthetic events.\n\t\t// Sequence: beforeinput -> mutation -> input -> change -> blur\n","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/alibaba/page-agent/blob/d02db1ee7c41f5315beda88bab2fe935c580f662/packages/page-controller/src/actions.ts#L116-L152","documentation":"inputTextElement only accepts <input>, <textarea>, or contenteditable elements; anything else (div, button, span) throws this error. Text entry requires a value-bearing or editable surface, so the library validates the element kind before typing. Receiving a non-editable element usually means the wrong index was chosen or the element role changed.","triggerScenarios":"Calling inputText on an index pointing to a <div>, <button>, <label>, or any non-editable element; the input was replaced by a rich-text div that is not contenteditable; acting on a container/wrapper instead of the inner <input> (common with custom dropdowns and search boxes).","commonSituations":"LLM picks the visible label/wrapper instead of the inner input; custom components render a fake input div without contenteditable; the field switched to readonly/disabled custom widget between observation and action.","solutions":["Inspect the simplified HTML and target the index of the actual <input>/<textarea> or a contenteditable node","For wrapper components, click the wrapper first to focus, then find the revealed input and type into it","Guard before typing: check element.tagName or isContentEditable","If the site uses a fake-input div, consider dispatching keyboard events instead of inputText"],"exampleFix":"// before\nawait controller.inputText(12, 'query') // index 12 is a <div>\n\n// after\nawait controller.updateTree()\n// find the real input element index (e.g. 13) in getSimplifiedHTML()\nawait controller.inputText(13, 'query')","handlingStrategy":"type-guard","validationCode":"const el = await controller.element(i); if (!el) return; if (!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) && !el.isContentEditable) { /* click to reveal the real input, re-index, skip inputText */ }","typeGuard":"function isTextEntryTarget(el: HTMLElement): boolean { return el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el.isContentEditable }","tryCatchPattern":"try { await controller.inputText(i, text) } catch (e) { if (String(e).includes('not an input, textarea, or contenteditable')) { await controller.clickElement(i); await controller.updateTree(); /* find revealed input */ } else throw e }","preventionTips":["Target the inner input/textarea index, not the visible wrapper","Verify editability from the simplified HTML before typing","For rich-text UIs, confirm a contenteditable attribute exists"],"tags":["dom","input","text-entry","page-controller"],"backgroundTag":"element-not-editable","analyzedSha":"d02db1ee7c41f5315beda88bab2fe935c580f662","analyzedAt":"2026-08-28T19:39:48.634Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}