microsoft/playwright · error · Error

At least one of "files" or "data" must be provided.

Error message

At least one of "files" or "data" must be provided.

What it means

Thrown by Frame.drop() when neither files (payloads, localPaths, or streams) nor data items are provided in the drop params. The method checks all three file-related properties and the data array; if all are empty or undefined, it refuses to execute the drag-and-drop operation since there is nothing to drop.

Source

Thrown at packages/playwright-core/src/server/frames.ts:1461

  async hover(progress: Progress, selector: string, options: types.PointerActionOptions & types.PointerActionWaitOptions) {
    return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._hover(progress, options)));
  }

  async selectOption(progress: Progress, selector: string, elements: dom.ElementHandle[], values: types.SelectOption[], options: types.CommonActionOptions): Promise<string[]> {
    return await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._selectOption(progress, elements, values, options));
  }

  async setInputFiles(progress: Progress, selector: string, params: Omit<channels.FrameSetInputFilesParams, 'timeout'> & { noAutoWaiting?: boolean }): Promise<channels.FrameSetInputFilesResult> {
    const inputFileItems = await progress.race(prepareFilesForUpload(this, params));
    return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, params, (progress, handle) => handle._setInputFiles(progress, inputFileItems)));
  }

  async drop(progress: Progress, selector: string, params: Omit<channels.FrameDropParams, 'timeout' | 'selector'>, options: types.PointerActionWaitOptions): Promise<void> {
    const hasFiles = !!(params.payloads?.length || params.localPaths?.length || params.streams?.length);
    const hasData = !!params.data?.length;
    if (!hasFiles && !hasData)
      throw new Error('At least one of "files" or "data" must be provided.');
    const inputFileItems = hasFiles ? await progress.race(prepareFilesForUpload(this, params)) : { filePayloads: undefined, localPaths: undefined };
    const data = params.data ?? [];
    dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._drop(progress, inputFileItems, data, options)));
  }

  async type(progress: Progress, selector: string, text: string, options: { delay?: number, noAutoWaiting?: boolean } & types.StrictOptions) {
    return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._type(progress, text, options)));
  }

  async press(progress: Progress, selector: string, key: string, options: { delay?: number, noWaitAfter?: boolean, noAutoWaiting?: boolean } & types.StrictOptions) {
    return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._press(progress, key, options)));
  }

  async check(progress: Progress, selector: string, options: types.PointerActionWaitOptions) {
    return dom.assertDone(await this._retryWithProgressIfNotConnected(progress, selector, options, (progress, handle) => handle._setChecked(progress, true, options)));
  }

  async uncheck(progress: Progress, selector: string, options: types.PointerActionWaitOptions) {

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Provide at least one file via { payloads: [{ name, mimeType, buffer }] } or { localPaths: ['/path/to/file'] }, or at least one data item via { data: [{ type: 'text/plain', data: 'hello' }] }.
  2. Validate that your file/data arrays are non-empty before calling drop: if (files.length === 0 && data.length === 0) return.
  3. Check that file-reading code upstream did not silently produce empty arrays.

Example fix

// before
await page.dragAndDrop('#source', '#target', { payloads: [] });

// after
await page.dragAndDrop('#source', '#target', {
  payloads: [{ name: 'file.txt', mimeType: 'text/plain', buffer: Buffer.from('hello') }]
});
Defensive patterns

Strategy: validation

Validate before calling

function validateDropParams(params) {
  const hasFiles = !!(params.payloads?.length || params.localPaths?.length || params.streams?.length);
  const hasData = !!params.data?.length;
  if (!hasFiles && !hasData)
    throw new Error('Drop requires at least files or data');
}

Type guard

function hasDropContent(params: any): boolean {
  return (Array.isArray(params.payloads) && params.payloads.length > 0)
    || (Array.isArray(params.localPaths) && params.localPaths.length > 0)
    || (Array.isArray(params.streams) && params.streams.length > 0)
    || (Array.isArray(params.data) && params.data.length > 0);
}

Prevention

When it happens

Trigger: Calling page.dragAndDrop() or frame.drop() with a params object that has empty payloads, localPaths, and streams arrays and an empty or missing data array. This can happen when the params are built dynamically and all source arrays resolve to empty.

Common situations: Building the drop params from a file list that is empty due to a prior filter or validation step. Passing a variable for files/data that is undefined at runtime. Migrating from a different drag-and-drop API that used different property names.

Related errors


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