{"record":{"id":"4226fc471cb269ef","repo":"microsoft/playwright","slug":"cannot-set-input-files-to-detached-input-element","errorCode":null,"errorMessage":"Cannot set input files to detached input element","messagePattern":"Cannot set input files to detached input element","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/chromium/crPage.ts","lineNumber":340,"sourceCode":"    }).catch(() => {});\n  }\n\n  stopScreencast() {\n    this._mainFrameSession._client._sendMayFail('Page.stopScreencast').catch(() => {});\n  }\n\n  rafCountForStablePosition(): number {\n    return 1;\n  }\n\n  async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {\n    return this._sessionForHandle(handle)._getContentQuads(handle);\n  }\n\n  async setInputFilePaths(progress: Progress, handle: dom.ElementHandle<HTMLInputElement>, files: string[]): Promise<void> {\n    const frame = await handle.ownerFrame(progress);\n    if (!frame)\n      throw new Error('Cannot set input files to detached input element');\n    const parentSession = this._sessionForFrame(frame);\n    await progress.race(parentSession._client.send('DOM.setFileInputFiles', {\n      objectId: handle._objectId,\n      files\n    }));\n  }\n\n  async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {\n    return this._sessionForHandle(handle)._adoptElementHandle<T>(handle, to);\n  }\n\n  async inputActionEpilogue(): Promise<void> {\n    await this._mainFrameSession._client.send('Page.enable').catch(e => {});\n  }\n\n  async resetForReuse(progress: Progress): Promise<void> {\n    // See https://github.com/microsoft/playwright/issues/22432.\n    await this.rawMouse.move(progress, -1, -1, 'none', new Set(), new Set(), true);","sourceCodeStart":322,"sourceCodeEnd":358,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/chromium/crPage.ts#L322-L358","documentation":"Thrown by CRPage.setInputFilePaths (crPage.ts:340) when handle.ownerFrame(progress) returns null — the input element no longer belongs to any frame, i.e. it has been detached from the DOM. Without an owning frame there is no frame session to send DOM.setFileInputFiles to.","triggerScenarios":"Calling locator.setInputFiles() on an <input> that an SPA re-render removed; the input being detached between action resolution and the CDP call; replaced forms during async setup.","commonSituations":"React/Vue/Svelte re-rendering the input after state changes; file inputs inside components that remount on validation; uploads triggered after a navigation that swapped the form.","solutions":["Re-query the locator right before setInputFiles so it resolves to the current element.","Use locator.waitFor({ state: 'visible' }) before the upload to ensure stability.","Anchor the input with a stable data-testid and a strict locator so re-renders do not invalidate it."],"exampleFix":"// before\nconst input = page.locator('input[type=file]');\nawait someAsyncWork();\nawait input.setInputFiles('/tmp/a.png');\n// after\nawait page.locator('[data-testid=upload]').waitFor({ state: 'visible' });\nawait page.locator('[data-testid=upload]').setInputFiles('/tmp/a.png');","handlingStrategy":"retry","validationCode":"// Stabilize the input before uploading.\nconst upload = page.locator('[data-testid=upload]');\nawait upload.waitFor({ state: 'visible' });\nawait upload.setInputFiles('/tmp/a.png');","typeGuard":null,"tryCatchPattern":"async function stableSetInputFiles(loc: Locator, files: string[]) {\n  for (let i = 0; i < 3; i++) {\n    try {\n      await loc.setInputFiles(files);\n      return;\n    } catch (e) {\n      if (!/detached input element/.test(String((e as Error).message)) || i === 2) throw e;\n      await loc.waitFor({ state: 'visible' });\n    }\n  }\n}","preventionTips":["Use a stable data-testid on file inputs so re-renders do not invalidate the locator.","Re-query the locator right before setInputFiles.","waitFor the input's visibility before uploading in SPAs."],"tags":["input","lifecycle","dom","chromium"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}