{"record":{"id":"ec4e0492e2bda751","repo":"microsoft/playwright","slug":"cannot-set-input-files-to-detached-element","errorCode":null,"errorMessage":"Cannot set input files to detached element","messagePattern":"Cannot set input files to detached element","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/client/elementHandle.ts","lineNumber":154,"sourceCode":"  }\n\n  async selectOption(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {\n    const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options }, this._frame._timeout(options));\n    return result.values;\n  }\n\n  async fill(value: string, options: channels.ElementHandleFillOptions & TimeoutOptions = {}): Promise<void> {\n    return await this._elementChannel.fill({ value, ...options }, this._frame._timeout(options));\n  }\n\n  async selectText(options: channels.ElementHandleSelectTextOptions & TimeoutOptions = {}): Promise<void> {\n    await this._elementChannel.selectText({ ...options }, this._frame._timeout(options));\n  }\n\n  async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions & TimeoutOptions = {}) {\n    const frame = await this.ownerFrame();\n    if (!frame)\n      throw new Error('Cannot set input files to detached element');\n    const converted = await convertInputFiles(files, frame.page().context());\n    await this._elementChannel.setInputFiles({ ...converted, ...options }, this._frame._timeout(options));\n  }\n\n  async focus(): Promise<void> {\n    await this._elementChannel.focus({}, kNoTimeout);\n  }\n\n  async type(text: string, options: channels.ElementHandleTypeOptions & TimeoutOptions = {}): Promise<void> {\n    await this._elementChannel.type({ text, ...options }, this._frame._timeout(options));\n  }\n\n  async press(key: string, options: channels.ElementHandlePressOptions & TimeoutOptions = {}): Promise<void> {\n    await this._elementChannel.press({ key, ...options }, this._frame._timeout(options));\n  }\n\n  async check(options: channels.ElementHandleCheckOptions & TimeoutOptions = {}) {\n    return await this._elementChannel.check({ ...options }, this._frame._timeout(options));","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/client/elementHandle.ts#L136-L172","documentation":"Thrown by ElementHandle.setInputFiles when ownerFrame() returns null/undefined. ownerFrame() resolves the frame owning the element; a null result means the node is detached from the document (no associated frame), so file upload cannot be dispatched. Unlike most element methods, setInputFiles needs a live frame to convert and stream the files.","triggerScenarios":"Acquiring an ElementHandle to an <input type=file>, then navigating/reloading/removing the node before calling setInputFiles. Also when the handle was obtained on a detached DOM node, or after the page closed.","commonSituations":"Caching an input handle across a navigation or SPA route change; the element being removed from the DOM (React/Vue re-render) between query and upload; operating on a handle from a previous page instance.","solutions":["Re-query the input immediately before setInputFiles, ideally via a Locator: page.locator('input[type=file]').setInputFiles(...).","Ensure the page is on the intended URL and the element is attached before the call.","Await any navigation/reload before touching file inputs.","Use expect(locator).toBeAttached() as a precondition."],"exampleFix":"// before\nconst input = await page.$('input[type=file]');\nawait page.goto(nextUrl); // detaches the node\nawait input.setInputFiles('/tmp/a.csv');\n\n// after\nawait page.goto(nextUrl);\nawait page.locator('input[type=file]').setInputFiles('/tmp/a.csv');","handlingStrategy":"type-guard","validationCode":"// Use a Locator + toBeAttached precondition instead of a cached handle.\nawait expect(page.locator('input[type=file]')).toBeAttached();\nawait page.locator('input[type=file]').setInputFiles(path);","typeGuard":"import type { ElementHandle } from 'playwright-core';\n\nasync function isAttached(handle: ElementHandle): Promise<boolean> {\n  return await handle.evaluate(el => el.isConnected).catch(() => false);\n}","tryCatchPattern":"try {\n  await input.setInputFiles(path);\n} catch (e) {\n  if (/Cannot set input files to detached element/.test(String(e?.message))) {\n    // Re-query via Locator and retry.\n    await page.locator(sel).setInputFiles(path);\n  } else throw e;\n}","preventionTips":["Use page.locator(...).setInputFiles, not a cached ElementHandle.","Await navigation/reload before touching inputs.","Use expect(locator).toBeAttached() as a precondition."],"tags":["element-handle","file-upload","lifecycle"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}