microsoft/playwright · error · Error

Cannot set input files to detached element

Error message

Cannot set input files to detached element

What it means

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.

Source

Thrown at packages/playwright-core/src/client/elementHandle.ts:154

  }

  async selectOption(values: string | api.ElementHandle | SelectOption | string[] | api.ElementHandle[] | SelectOption[] | null, options: SelectOptionOptions = {}): Promise<string[]> {
    const result = await this._elementChannel.selectOption({ ...convertSelectOptionValues(values), ...options }, this._frame._timeout(options));
    return result.values;
  }

  async fill(value: string, options: channels.ElementHandleFillOptions & TimeoutOptions = {}): Promise<void> {
    return await this._elementChannel.fill({ value, ...options }, this._frame._timeout(options));
  }

  async selectText(options: channels.ElementHandleSelectTextOptions & TimeoutOptions = {}): Promise<void> {
    await this._elementChannel.selectText({ ...options }, this._frame._timeout(options));
  }

  async setInputFiles(files: string | FilePayload | string[] | FilePayload[], options: channels.ElementHandleSetInputFilesOptions & TimeoutOptions = {}) {
    const frame = await this.ownerFrame();
    if (!frame)
      throw new Error('Cannot set input files to detached element');
    const converted = await convertInputFiles(files, frame.page().context());
    await this._elementChannel.setInputFiles({ ...converted, ...options }, this._frame._timeout(options));
  }

  async focus(): Promise<void> {
    await this._elementChannel.focus({}, kNoTimeout);
  }

  async type(text: string, options: channels.ElementHandleTypeOptions & TimeoutOptions = {}): Promise<void> {
    await this._elementChannel.type({ text, ...options }, this._frame._timeout(options));
  }

  async press(key: string, options: channels.ElementHandlePressOptions & TimeoutOptions = {}): Promise<void> {
    await this._elementChannel.press({ key, ...options }, this._frame._timeout(options));
  }

  async check(options: channels.ElementHandleCheckOptions & TimeoutOptions = {}) {
    return await this._elementChannel.check({ ...options }, this._frame._timeout(options));

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Re-query the input immediately before setInputFiles, ideally via a Locator: page.locator('input[type=file]').setInputFiles(...).
  2. Ensure the page is on the intended URL and the element is attached before the call.
  3. Await any navigation/reload before touching file inputs.
  4. Use expect(locator).toBeAttached() as a precondition.

Example fix

// before
const input = await page.$('input[type=file]');
await page.goto(nextUrl); // detaches the node
await input.setInputFiles('/tmp/a.csv');

// after
await page.goto(nextUrl);
await page.locator('input[type=file]').setInputFiles('/tmp/a.csv');
Defensive patterns

Strategy: type-guard

Validate before calling

// Use a Locator + toBeAttached precondition instead of a cached handle.
await expect(page.locator('input[type=file]')).toBeAttached();
await page.locator('input[type=file]').setInputFiles(path);

Type guard

import type { ElementHandle } from 'playwright-core';

async function isAttached(handle: ElementHandle): Promise<boolean> {
  return await handle.evaluate(el => el.isConnected).catch(() => false);
}

Try / catch

try {
  await input.setInputFiles(path);
} catch (e) {
  if (/Cannot set input files to detached element/.test(String(e?.message))) {
    // Re-query via Locator and retry.
    await page.locator(sel).setInputFiles(path);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/ec4e0492e2bda751. Report an issue: GitHub.