# How to Upload Files in ego-browser Using the setInputFiles Helper

> Learn to upload files in ego-browser with setInputFiles. Programmatically upload files to input type file elements using Chrome DevTools Protocol for seamless testing.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-07-30

---

**The `setInputFiles` helper lets you programmatically upload files to `<input type="file">` elements by resolving element handles and injecting absolute file paths directly via Chrome DevTools Protocol (CDP).**

The `ego-browser` package from the `citrolabs/ego-lite` repository provides this helper to automate file selection without interacting with OS-level file dialogs. By leveraging CDP's `DOM.setFileInputFiles` method, the helper directly attaches files to input elements, supporting single and multiple file uploads through various invocation patterns.

## Where the Helper is Defined

The `setInputFiles` functionality spans several key files in the codebase. The public API is exported from **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** at line 99, which makes the helper available to automation scripts. The actual implementation resides in **[`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts)**, where the function resolves element references and invokes the CDP command. Underlying element handle management is handled by utilities in **[`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts)**, specifically the `withHandle` and `resolveHandle` functions that safely manage CDP object lifecycles.

## How setInputFiles Works

The helper operates through a three-stage pipeline that bridges high-level JavaScript calls with low-level browser automation.

### Element Resolution

First, `setInputFiles` receives a selector string—supporting CSS selectors, `@ref` syntax, or `loc=` patterns—and delegates to `withHandle` in [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts). This utility calls `resolveHandle` → `resolveElementObjectId` to obtain a CDP `objectId` for the target element, ensuring the handle is released after use to prevent memory leaks (see lines 45–51 in [`element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/element-ops.ts)).

### CDP File Injection

With the `objectId` secured, the implementation in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) (lines 11–13) invokes the Chrome DevTools Protocol:

```javascript
await cdp("DOM.setFileInputFiles", { files, objectId }, sessionId);

```

The `files` parameter is an array of absolute file paths that the Chrome/Edge runtime reads directly from the host file system. This bypasses the need for synthetic click events or OS dialog interactions.

### Result

After successful execution, the `<input type="file">` element contains the specified files. You can then trigger form submission with a standard `click()` on a submit button or proceed with other form interactions.

## Usage Patterns

The helper supports three distinct invocation styles, all accepting either a single string or an array of strings for file paths.

### Global Helper Syntax

Call the exported helper directly with a selector and file path:

```javascript
await setInputFiles('input[name="avatar"]', '/home/user/photo.png');

```

This style imports `setInputFiles` from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) and executes the upload immediately.

### Locator Method Syntax

Use the locator proxy method for chainable interactions:

```javascript
await page
  .locator('input[name="attachments"]')
  .setInputFiles(['/tmp/report.docx', '/tmp/image.png']);

```

This pattern, wired in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) (lines 77–78), forwards to the same underlying driver code while maintaining the fluent locator API.

### Ref-based Syntax

Reference elements captured in previous snapshots using the `@ref` notation:

```javascript
await setInputFiles('@42', '/var/data/config.json');

```

This approach skips re-querying the DOM by using the stored object reference from a prior snapshot.

## Critical Requirements

**Absolute paths required**: The CDP runtime cannot resolve relative paths. Use `path.resolve()` in your script to convert relative paths to absolute ones before passing them to the helper.

**File accessibility**: The host process must have read permissions for the specified files. If the file is inaccessible, the CDP call throws a "file not found" error.

**Multiple files**: Pass an array of strings to upload several files simultaneously to inputs that accept multiple selections.

## Code Examples

```javascript
// Single file upload using the global helper
await setInputFiles('input[type="file"]#resume', '/home/user/Resume.pdf');

// Uploading multiple files via locator chain
const uploadBtn = page.locator('button#send');
await page
  .locator('input[name="attachments"]')
  .setInputFiles(['/tmp/report.docx', '/tmp/image.png']);
await uploadBtn.click();

// Using a previously saved ref (e.g., @23 from a snapshot)
await setInputFiles('@23', '/var/data/config.json');

```

## Summary

- **`setInputFiles`** is the primary helper for file uploads in ego-browser, exported from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) and implemented in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts).
- It uses **CDP's `DOM.setFileInputFiles`** to inject files directly into `<input type="file">` elements without OS dialog interaction.
- The helper requires **absolute file paths** and handles **single or multiple files** via string or array arguments.
- Three invocation styles are supported: **global helper**, **locator method**, and **ref-based** addressing.
- Element resolution is safely managed through `withHandle` utilities in [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts) to prevent handle leaks.

## Frequently Asked Questions

### What is the difference between setInputFiles and a normal click upload?

**`setInputFiles`** bypasses the browser's native file picker dialog by directly manipulating the input element's FileList through Chrome DevTools Protocol. This is more reliable than simulating clicks on file inputs, which would require complex OS-level automation to handle the system file dialog.

### Can I use relative file paths with the ego-browser uploadFile helper?

No. The underlying CDP `DOM.setFileInputFiles` method requires absolute file paths. You must resolve relative paths using `path.resolve()` or `__dirname` concatenation before passing them to `setInputFiles`, otherwise the Chrome runtime will fail to locate the files.

### How do I upload multiple files to a single input element?

Pass an array of absolute file paths as the second argument:

```javascript
await setInputFiles('input[multiple]', ['/path/to/file1.pdf', '/path/to/file2.pdf']);

```

Ensure the input element has the `multiple` attribute; otherwise, the browser may only accept the first file in the array.

### Why am I getting a "file not found" error when using setInputFiles?

This error occurs when the Chrome/Edge process running the automation cannot access the file at the specified absolute path. Verify that the file exists, the path is absolute (not relative), and the Node.js process has read permissions for that file location. Network paths or files inside restricted directories may also cause this error.