grafana/k6 · error

setting input files

Error message

setting input files: %w

What it means

Thrown by the k6 browser module's ElementHandle.setInputFiles(). It wraps any failure of the setInputFiles action: timeout, element detached, or the injected script returning a DOM error — most typically 'node is not an input[type=file] element' (error:notfile) or 'non-multiple file input can only accept single file' (error:notmultiplefileinput).

Solutions

  1. Target the real file input: const input = await page.waitForSelector('input[type=file]') — often hidden, so use page.waitForSelector with state 'attached' and then call setInputFiles (it works on hidden inputs).
  2. Pass exactly one file when the input lacks the multiple attribute.
  3. Re-query the handle right before the call so it is attached to the current DOM.
  4. Increase the timeout: el.setInputFiles(files, { timeout: '60s' }).

Example fix

// before
const btn = await page.$('.upload-button');
await btn.setInputFiles([{ name: 'a.png', mimeType: 'image/png', data: ... }]); // not a file input

// after
const input = await page.waitForSelector('input[type="file"]');
await input.setInputFiles([{ name: 'a.png', mimeType: 'image/png', data: pngBytes }], { timeout: '30s' });
Defensive patterns

Strategy: validation

Validate before calling

const isFileInput = await el.evaluate(n => n.tagName === 'INPUT' && n.type === 'file');
if (!isFileInput) {
  throw new Error('setInputFiles target must be input[type=file]');
}
const multiple = await el.evaluate(n => n.multiple);
if (!multiple && files.length > 1) {
  throw new Error('input lacks multiple attribute; pass a single file');
}
await el.setInputFiles(files, { timeout: '30s' });

Type guard

async function isFileInput(el) {
  if (!el) return false;
  return await el.evaluate(n => n instanceof HTMLInputElement && n.type === 'file').catch(() => false);
}

Try / catch

try {
  await el.setInputFiles(files, { timeout: '30s' });
} catch (e) {
  if (String(e).includes('not an input[type=file]')) {
    const input = await page.waitForSelector('input[type="file"]');
    await input.setInputFiles(files, { timeout: '30s' });
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling el.setInputFiles(...) on an <input> that is not type=file; passing multiple files in the payload to an <input> without the multiple attribute; the file input being re-created by the framework and the handle going stale; timeout before the element is actionable.

Common situations: Drag-and-drop styled upload widgets that hide the real <input type=file> behind a button — developers select the visible button instead of the hidden input; React re-rendering the upload control after a failed upload, detaching the old handle.

Related errors


AI-assisted analysis of grafana/k6@3fcf5388d7 (2026-08-18). Data as JSON: /api/errors/3b51f3789d759e41. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/element_handle.go:1465

		[]string{}, selectText, opts.Force, withRetry, opts.NoWaitAfter, opts.Timeout,
	)
	if _, err := call(h.ctx, selectTextAction, opts.Timeout); err != nil {
		return fmt.Errorf("selecting text: %w", err)
	}

	applySlowMo(h.ctx)

	return nil
}

// SetInputFiles sets the given files into the input file element.
func (h *ElementHandle) SetInputFiles(files *Files, opts *ElementHandleSetInputFilesOptions) error {
	setInputFiles := func(apiCtx context.Context, handle *ElementHandle) (any, error) {
		return nil, handle.setInputFiles(apiCtx, files)
	}
	setInputFilesAction := h.newAction([]string{}, setInputFiles, opts.Force, withRetry, opts.NoWaitAfter, opts.Timeout)
	if _, err := call(h.ctx, setInputFilesAction, opts.Timeout); err != nil {
		return fmt.Errorf("setting input files: %w", err)
	}

	return nil
}

func (h *ElementHandle) setInputFiles(apiCtx context.Context, files *Files) error {
	// allow clearing the input by passing an empty array
	var payload []*File
	if files != nil {
		payload = files.Payload
	}
	fn := `
		(node, injected, payload) => {
			return injected.setInputFiles(node, payload);
		}
	`
	evalOpts := evalOptions{
		forceCallable: true,

View on GitHub (pinned to 3fcf5388d7)