microsoft/playwright · error · Error
Cannot set input files to detached input element
Error message
Cannot set input files to detached input element
What it means
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.
Source
Thrown at packages/playwright-core/src/server/chromium/crPage.ts:340
}).catch(() => {});
}
stopScreencast() {
this._mainFrameSession._client._sendMayFail('Page.stopScreencast').catch(() => {});
}
rafCountForStablePosition(): number {
return 1;
}
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
return this._sessionForHandle(handle)._getContentQuads(handle);
}
async setInputFilePaths(progress: Progress, handle: dom.ElementHandle<HTMLInputElement>, files: string[]): Promise<void> {
const frame = await handle.ownerFrame(progress);
if (!frame)
throw new Error('Cannot set input files to detached input element');
const parentSession = this._sessionForFrame(frame);
await progress.race(parentSession._client.send('DOM.setFileInputFiles', {
objectId: handle._objectId,
files
}));
}
async adoptElementHandle<T extends Node>(handle: dom.ElementHandle<T>, to: dom.FrameExecutionContext): Promise<dom.ElementHandle<T>> {
return this._sessionForHandle(handle)._adoptElementHandle<T>(handle, to);
}
async inputActionEpilogue(): Promise<void> {
await this._mainFrameSession._client.send('Page.enable').catch(e => {});
}
async resetForReuse(progress: Progress): Promise<void> {
// See https://github.com/microsoft/playwright/issues/22432.
await this.rawMouse.move(progress, -1, -1, 'none', new Set(), new Set(), true);View on GitHub (pinned to c8fc3bf8d3)
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.
Example fix
// before
const input = page.locator('input[type=file]');
await someAsyncWork();
await input.setInputFiles('/tmp/a.png');
// after
await page.locator('[data-testid=upload]').waitFor({ state: 'visible' });
await page.locator('[data-testid=upload]').setInputFiles('/tmp/a.png'); Defensive patterns
Strategy: retry
Validate before calling
// Stabilize the input before uploading.
const upload = page.locator('[data-testid=upload]');
await upload.waitFor({ state: 'visible' });
await upload.setInputFiles('/tmp/a.png'); Try / catch
async function stableSetInputFiles(loc: Locator, files: string[]) {
for (let i = 0; i < 3; i++) {
try {
await loc.setInputFiles(files);
return;
} catch (e) {
if (!/detached input element/.test(String((e as Error).message)) || i === 2) throw e;
await loc.waitFor({ state: 'visible' });
}
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Frame has been detached.
- Unable to adopt element handle from a different document
- PDF creation is only working with Chromium
- The object has been collected to prevent unbounded heap grow
- Cannot find object to "${method}": ${guid}
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/4226fc471cb269ef.
Report an issue: GitHub.