# Coco App `upload_attachment` Requirements and File Storage Reference Guide

> Learn Coco App upload_attachment requirements and file storage. Discover how to upload files and reference them using unique IDs for easy retrieval from the Coco server.

- Repository: [INFINI Labs/coco-app](https://github.com/infinilabs/coco-app)
- Tags: api-reference
- Published: 2026-03-04

---

**The `upload_attachment` Tauri command requires a valid server ID, absolute file paths with UTF-8 filenames, and returns unique attachment IDs that are later referenced via `get_attachment_by_ids` to retrieve stored files from the Coco server.**

In the infinilabs/coco-app repository, attachment handling is implemented as a core Tauri command that bridges the frontend and a remote Coco server. Understanding the strict validation requirements and the identifier-based storage pattern is essential for building file upload features that integrate properly with the chat and assistant workflows.

## Prerequisites for upload_attachment

Before invoking the command, the system validates several constraints defined in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs). Failure to meet any requirement results in specific error variants returned to the caller.

### Server Configuration Requirements

The command accepts a **`server_id`** parameter that must reference an existing server configuration registered in the application. According to the implementation in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs) (lines 96-101), if the provided ID does not correspond to a known server, the command returns a `ServerNotFound` error immediately.

Additionally, if the target server configuration includes an API token, the command automatically attaches it as an `X-API-TOKEN` header during the HTTP request (lines 104-108).

### File Path and Naming Constraints

The **`file_paths`** parameter must be a `Vec<PathBuf>` containing absolute paths to existing, readable files. The implementation performs the following validations:

- **File existence**: Each path is checked to confirm it points to a valid file on the local filesystem (lines 61-73).
- **Filename extraction**: The path must yield a filename that can be extracted for the multipart upload (lines 78-82).
- **UTF-8 encoding**: The filename must be valid UTF-8; otherwise, the command returns a `NonUtf8Filename` error (lines 84-88).

## How Attachments Are Stored and Referenced

The storage lifecycle follows a distributed identifier pattern: files are uploaded once, referenced by immutable IDs in chat contexts, and retrieved on-demand via a dedicated search endpoint.

### Upload Response and Attachment IDs

Upon successful multipart upload, the Coco server returns an `UploadAttachmentResponse` struct containing:

- `acknowledged`: A boolean confirming receipt
- `attachments`: A `Vec<String>` of unique attachment identifiers

These identifiers are generated server-side and serve as the canonical reference for the files. The struct definition is found in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs) (lines 17-24).

### Linking Attachments to Chat Sessions

The returned IDs are not automatically persisted; the caller must explicitly include them in subsequent chat operations. As defined in [`src-tauri/src/common/assistant.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/common/assistant.rs) (lines 8-10), requests to `chat_create` or `chat_chat` accept an optional `attachments` field of type `Option<Vec<String>>`.

The typical flow stores these IDs in the `SessionContext.attachments` vector before initiating a conversation, ensuring the server associates the uploaded files with the specific chat session.

### Retrieving Files with get_attachment_by_ids

To access stored files later, the system uses the **`get_attachment_by_ids`** command implemented in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs) (lines 27-49). This function:

1. Accepts a `server_id` and a `Vec<String>` of attachment IDs
2. Constructs a JSON body: `{"attachments": ["id1", "id2"]}`
3. POSTs to the `/attachment/_search` endpoint
4. Returns the raw JSON payload containing URLs or binary metadata

This retrieval pattern decouples the upload operation from file consumption, allowing attachments to be referenced across multiple sessions without re-uploading.

## Implementation Examples

### Uploading Files from the Frontend

Invoke the command from JavaScript using the Tauri API:

```javascript
async function uploadFiles(serverId, filePaths) {
  try {
    const response = await window.__TAURI__.invoke('upload_attachment', {
      server_id: serverId,
      file_paths: filePaths  // Array of absolute paths
    });
    
    // response: { acknowledged: true, attachments: ['abc123', 'def456'] }
    console.log('Attachment IDs:', response.attachments);
    return response.attachments;
  } catch (e) {
    console.error('Upload failed:', e);
    throw e;
  }
}

// Example usage
uploadFiles('production-server', ['/Users/me/report.pdf', '/Users/me/data.csv']);

```

### Attaching Files to Chat Requests

When constructing a chat request in Rust, include the IDs returned from `upload_attachment`:

```rust
use serde_json::json;

// `ids` is the Vec<String> returned from upload_attachment
let chat_payload = json!({
    "message": "Please analyze these documents",
    "attachments": ids  // Links files to this message
});

```

This structure is processed by the chat orchestration layer in [`src-tauri/src/assistant/mod.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/assistant/mod.rs).

### Fetching Stored Attachments

Retrieve metadata or URLs for previously uploaded files:

```rust
// Within a Tauri command or async context
let attachment_ids = vec!["abc123".to_string(), "def456".to_string()];
let payload = get_attachment_by_ids(server_id, attachment_ids).await?;
println!("Retrieved: {}", payload);

```

From the frontend:

```javascript
const results = await window.__TAURI__.invoke('get_attachment_by_ids', {
  server_id: 'production-server',
  attachments: ['abc123', 'def456']
});

```

## Summary

- **`upload_attachment`** requires a valid `server_id`, absolute file paths, and UTF-8 filenames, returning `NonUtf8Filename` or `ServerNotFound` errors when constraints are violated.
- **Authentication** is handled automatically via the `X-API-TOKEN` header when the server configuration includes an API token.
- **Storage references** are immutable string IDs returned in the `UploadAttachmentResponse`, not the files themselves.
- **Chat integration** occurs by passing these IDs to the `attachments` parameter in chat creation or messaging requests.
- **Retrieval** is performed via `get_attachment_by_ids`, which queries the `/attachment/_search` endpoint with a JSON body containing the ID list.

## Frequently Asked Questions

### What happens if a filename contains non-UTF-8 characters?

The `upload_attachment` command in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs) (lines 84-88) explicitly validates UTF-8 encoding. If the filename contains invalid UTF-8 sequences, the command returns a `NonUtf8Filename` error before attempting the upload. The caller must sanitize or rename the file before retrying.

### How are authentication tokens handled during upload?

If the server configuration associated with the provided `server_id` contains an `api_token` field, the command automatically injects it into the request headers as `X-API-TOKEN`. This occurs during the HTTP client construction phase in [`src-tauri/src/server/attachment.rs`](https://github.com/infinilabs/coco-app/blob/main/src-tauri/src/server/attachment.rs) (lines 104-108), requiring no manual header management from the frontend.

### Can I upload multiple files in a single request?

Yes. The `file_paths` parameter accepts a `Vec<PathBuf>`, allowing batch uploads. The command iterates over all paths, validates each file individually, and constructs a multipart request containing all valid files. The server returns a corresponding list of attachment IDs in the `attachments` field of the response.

### Where are attachment IDs stored between upload and retrieval?

The Coco app does not persist attachment IDs automatically. The caller is responsible for storing the returned `Vec<String>` in application state, typically within a `SessionContext` struct, or passing them immediately to `chat_create` or `chat_chat` requests. The IDs are ephemeral references that must be maintained by the client until needed for retrieval via `get_attachment_by_ids`.