# How to Handle File Uploads Using `setInputFiles` in ego-lite

> Learn to handle file uploads with ego-lite's setInputFiles helper. This guide explains how to resolve selectors and send CDP commands for seamless file uploads to input elements.

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

---

**`ego-lite` provides the `setInputFiles` helper function to upload files to `<input type="file">` elements by resolving a selector and sending a CDP command to the browser.**

The `setInputFiles` function is the primary mechanism for handling file uploads in ego-lite agent scripts. It bridges high-level selector-based element targeting with Chrome DevTools Protocol (CDP) operations to attach local files to file input elements. This article examines the implementation in `citrolabs/ego-lite` and explains how to use it effectively.

## Where `setInputFiles` Lives in the Codebase

The function is implemented in **[`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts)** and exposed through multiple export layers to reach agent scripts.

| Component | Role | Location |
|---|---|---|
| `setInputFiles` | Core implementation | [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) (lines 10–15) |
| `withHandle` | Selector resolution utility | [`src/driver/element-ops.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/element-ops.ts) |
| `cdp` | CDP message wrapper | [`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts) |
| [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) | Public API re-export | lines 570–580 |
| [`index.ts`](https://github.com/citrolabs/ego-lite/blob/main/index.ts) | CLI/SDK entry point | line 121 |

This layered architecture ensures `setInputFiles` is available both as a direct import and within the injected helper context that ego-lite provides to running agents.

## How `setInputFiles` Works Internally

The function follows a four-step execution flow when an agent calls it:

1. **Selector resolution** — The `withHandle` utility converts the selector to a CDP `objectId` representing the DOM node.

2. **Path normalization** — Input strings are normalized to absolute paths; arrays are flattened for multi-file uploads.

3. **CDP command execution** — `cdp("DOM.setFileInputFiles", …)` sends file paths to the browser, which populates the input element's `files` property.

4. **Promise resolution** — Returns when the CDP call completes, throwing `ElementResolutionError` for permanent failures like missing elements or invalid file paths.

Since the operation uses CDP directly, it functions across all selector formats and automatically respects the current task-space session, including re-attachment if the session was interrupted.

## Supported Selector Formats

`setInputFiles` accepts any selector type that ego-lite's resolver handles:

- **CSS selectors**: `#upload`, `.file-input`, `[name="document"]`
- **XPath**: `xpath=//input[@type='file']`
- **Locator syntax**: `loc=css:#avatar` (used by site-skills)
- **Reference handles**: `@ref` (pre-resolved element references)

The resolver's flexibility means you can use the same selector patterns across all ego-lite helper functions.

## Code Examples for File Uploads

### Single File Upload

```javascript
// Upload a profile picture using a CSS selector
await setInputFiles('#profile-pic', '/home/user/pictures/avatar.png');

```

### Multiple File Upload

```javascript
// Upload multiple gallery images in one call
await setInputFiles('#gallery-upload', [
  '/home/user/photos/img1.jpg',
  '/home/user/photos/img2.jpg',
  '/home/user/photos/img3.png'
]);

```

### XPath and Locator Selectors

```javascript
// XPath selector for dynamic inputs
await setInputFiles('xpath=//input[@id="resume"]', '/tmp/resume.pdf');

// Site-skill generated locator
await setInputFiles('loc=css:#document-upload', '/var/docs/report.docx');

```

## Critical Requirements and Constraints

**Absolute paths are mandatory.** All file paths must be absolute and accessible from the process running the ego-lite binary. Relative paths or paths on remote systems will fail.

**Element validation is strict.** The target element must exist and be a valid file input. Attempting to call `setInputFiles` on non-file inputs triggers an `ElementResolutionError` with `permanent: true`, preventing automatic retries.

**Multi-file uploads require array input.** Pass an array even for single files if your code needs to handle variable counts dynamically.

## Error Handling Behavior

| Error Condition | Exception Type | Retry Behavior |
|---|---|---|
| Selector not found | `ElementResolutionError` | No retry (permanent) |
| Element is not a file input | `ElementResolutionError` | No retry (permanent) |
| File does not exist at path | System error | No retry |
| CDP transport failure | Connection error | May retry at session level |

## Summary

- **`setInputFiles`** in ego-lite wraps CDP's `DOM.setFileInputFiles` for reliable file uploads
- Implementation resides in [`src/driver/files.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/driver/files.ts) with public exposure through [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)
- Supports all ego-lite selector formats: CSS, XPath, `loc=`, and `@ref`
- Requires **absolute file paths** on the host running ego-lite
- Handles multiple files via array input
- Throws `ElementResolutionError` for permanent failures like invalid selectors or non-file inputs

## Frequently Asked Questions

### What file paths does `setInputFiles` accept?

`setInputFiles` requires **absolute paths** accessible from the ego-lite runtime process. Relative paths are not resolved automatically. For example, use `/home/user/doc.pdf` rather than `./doc.pdf` or `~/doc.pdf`.

### Can I upload multiple files at once?

Yes. Pass an array of absolute paths as the second argument: `await setInputFiles('#input', ['/path/1.jpg', '/path/2.jpg'])`. The order in the array matches the order in the input element's `files` property.

### What happens if the selector doesn't match a file input?

The function throws an `ElementResolutionError` with `kind: 'permanent'`. This error type prevents automatic task retries, surfacing the problem immediately to the agent script.

### Is `setInputFiles` available in all ego-lite execution contexts?

Yes. The function is re-exported through [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) into the injected helper scope and also available via [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) for direct SDK imports, making it accessible in both standalone scripts and integrated agent workflows.