electric-sql / electric-sql/electric

Fetch/Request subset snapshot returns data twice

Open
#4,140 0 comments 0 reactions 0 assignees View on GitHub
triage
Dominant language
TypeScript
Stars
10.4k
Forks
375
Avg merge
3d 1h
Merged PRs (30d)
18

Description

**Versions**

- Client: "@electric-sql/client": "^1.5.15",
- Electric: 1.5.1

**Bug description**
I'm using `fetchSnapshot()`.

I see that 2 network requests are made returning the same data but different `"snapshot_mark": 1981649824"`.

When minimising it towards only the example from [the docs](https://electric-sql.com/docs/guides/shapes#requesting-subset-snapshots). It also happens:
```ts
const stream = new ShapeStream({
url: 'http://localhost:3000/v1/shape',
params: { table: 'items' },
log: 'changes_only',
})

// Load high-priority items with pagination
const { metadata, data } = await stream.requestSnapshot({
where: "priority = $1",
params: { '1': 'high' },
orderBy: 'created_at DESC',
limit: 20,
offset: 0,
})
```

Note that i'm using `fetchSnapshot()` and not `requestSnapshot()`.

**Expected behavior**
I'm expecting only 1 network request with the data.

**Vid**

https://github.com/user-attachments/assets/367af5dc-4d61-40e6-bad1-a2c5df800e37

**Extra context**

```md
This isn’t your app doing two separate fetchSnapshot calls for the same page — it’s how the @electric-sql/client HTTP stack works for chunked shape responses.

What’s going on

1. First request (offset=now, no handle in the URL)

This is the initial request for that snapshot. The server answers with:
• the first chunk of the snapshot body, and
• response headers such as electric-handle and electric-offset (see SHAPE_HANDLE_HEADER / CHUNK_LAST_OFFSET_HEADER in the client).

2. Second request (same path, but now handle=… and offset=191558552_0)

The client builds a continuation URL from those headers and issues another GET. That comes from createFetchWithChunkBuffer + getNextChunkUrl in node_modules/@electric-sql/client/dist/index.mjs:
after a response, if there is a handle and last-offset and the snapshot is not marked up-to-date, it sets handle + offset on the URL for the next chunk and can prefetch it (the prefetch queue defaults
allow multiple chunk prefetches).

So you see two HTTP round-trips for one logical fetchSnapshot: first chunk + next chunk (often prefetched before you “need” it).
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.