Skip to content

Conversation

@darkgnotic
Copy link
Contributor

User report:

The code to initiate parallel fetching of config patches and row patches left one Promise without a catch handler until it gets awaited later on. If an exception happens before the await, Node crashes the server with an unhandled rejection error.

The fix is to install a catch handler ahead of time. It is okay to be a noop because the exception will be handled later when the promise is awaited. (Technically, it may be dropped if the row patches throws an error, but this is also okay).

@darkgnotic darkgnotic requested a review from grgbkr January 16, 2026 22:00
@vercel
Copy link

vercel bot commented Jan 16, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
replicache-docs Ready Ready Preview, Comment Jan 16, 2026 10:02pm
zbugs Ready Ready Preview, Comment Jan 16, 2026 10:02pm

Request Review

@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🐰 Bencher Report

Branchdarkgnotic/fix-unhandled-rejection
TestbedLinux
Click to view all benchmark results
BenchmarkFile SizeBenchmark Result
kilobytes (KB)
(Result Δ%)
Upper Boundary
kilobytes (KB)
(Limit %)
zero-package.tgz📈 view plot
🚷 view threshold
1,783.60 KB
(+0.00%)Baseline: 1,783.53 KB
1,819.20 KB
(98.04%)
zero.js📈 view plot
🚷 view threshold
242.90 KB
(0.00%)Baseline: 242.90 KB
247.76 KB
(98.04%)
zero.js.br📈 view plot
🚷 view threshold
66.56 KB
(0.00%)Baseline: 66.56 KB
67.89 KB
(98.04%)
🐰 View full continuous benchmarking report in Bencher

@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🐰 Bencher Report

Branchdarkgnotic/fix-unhandled-rejection
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
1 exists: track.exists(album)📈 view plot
🚷 view threshold
13,201.32 ops/s
(-5.26%)Baseline: 13,934.47 ops/s
11,656.19 ops/s
(88.30%)
10 exists (AND)📈 view plot
🚷 view threshold
198,254.39 ops/s
(-3.10%)Baseline: 204,597.58 ops/s
166,143.78 ops/s
(83.80%)
10 exists (OR)📈 view plot
🚷 view threshold
3,677.89 ops/s
(-8.07%)Baseline: 4,000.62 ops/s
3,360.29 ops/s
(91.36%)
12 exists (AND)📈 view plot
🚷 view threshold
161,426.47 ops/s
(-10.64%)Baseline: 180,640.14 ops/s
146,375.51 ops/s
(90.68%)
12 exists (OR)📈 view plot
🚷 view threshold
3,129.82 ops/s
(-7.91%)Baseline: 3,398.69 ops/s
2,871.56 ops/s
(91.75%)
12 level nesting📈 view plot
🚷 view threshold
2,808.30 ops/s
(-5.28%)Baseline: 2,964.81 ops/s
2,498.19 ops/s
(88.96%)
2 exists (AND): track.exists(album).exists(genre)📈 view plot
🚷 view threshold
4,906.45 ops/s
(-6.30%)Baseline: 5,236.18 ops/s
4,394.59 ops/s
(89.57%)
3 exists (AND)📈 view plot
🚷 view threshold
1,920.82 ops/s
(-5.98%)Baseline: 2,043.06 ops/s
1,719.16 ops/s
(89.50%)
3 exists (OR)📈 view plot
🚷 view threshold
977.63 ops/s
(-4.50%)Baseline: 1,023.69 ops/s
861.64 ops/s
(88.14%)
5 exists (AND)📈 view plot
🚷 view threshold
296.15 ops/s
(-7.85%)Baseline: 321.37 ops/s
270.41 ops/s
(91.31%)
5 exists (OR)📈 view plot
🚷 view threshold
154.33 ops/s
(-8.98%)Baseline: 169.55 ops/s
141.71 ops/s
(91.83%)
Nested 2 levels: track > album > artist📈 view plot
🚷 view threshold
4,252.25 ops/s
(-7.05%)Baseline: 4,574.70 ops/s
3,845.99 ops/s
(90.45%)
Nested 4 levels: playlist > tracks > album > artist📈 view plot
🚷 view threshold
736.45 ops/s
(-1.96%)Baseline: 751.19 ops/s
638.59 ops/s
(86.71%)
Nested with filters: track > album > artist (filtered)📈 view plot
🚷 view threshold
3,782.47 ops/s
(-0.52%)Baseline: 3,802.36 ops/s
3,228.50 ops/s
(85.35%)
planned: playlist.exists(tracks)📈 view plot
🚷 view threshold
599.32 ops/s
(-4.11%)Baseline: 625.01 ops/s
538.50 ops/s
(89.85%)
planned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
155.74 ops/s
(-6.12%)Baseline: 165.89 ops/s
145.67 ops/s
(93.53%)
planned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
7,401.83 ops/s
(-3.05%)Baseline: 7,634.48 ops/s
6,608.20 ops/s
(89.28%)
planned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
37.69 ops/s
(-4.99%)Baseline: 39.67 ops/s
33.84 ops/s
(89.79%)
planned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
5,143.21 ops/s
(-4.61%)Baseline: 5,392.02 ops/s
4,617.18 ops/s
(89.77%)
planned: track.exists(playlists)📈 view plot
🚷 view threshold
3.73 ops/s
(-7.41%)Baseline: 4.03 ops/s
3.48 ops/s
(93.16%)
unplanned: playlist.exists(tracks)📈 view plot
🚷 view threshold
582.91 ops/s
(-4.35%)Baseline: 609.45 ops/s
525.40 ops/s
(90.13%)
unplanned: track.exists(album) OR exists(genre)📈 view plot
🚷 view threshold
41.71 ops/s
(-7.43%)Baseline: 45.06 ops/s
38.14 ops/s
(91.44%)
unplanned: track.exists(album) where title="Big Ones"📈 view plot
🚷 view threshold
53.38 ops/s
(-5.76%)Baseline: 56.64 ops/s
48.49 ops/s
(90.83%)
unplanned: track.exists(album).exists(genre)📈 view plot
🚷 view threshold
37.46 ops/s
(-5.14%)Baseline: 39.49 ops/s
33.75 ops/s
(90.11%)
unplanned: track.exists(album).exists(genre) with filters📈 view plot
🚷 view threshold
52.08 ops/s
(-5.87%)Baseline: 55.33 ops/s
48.10 ops/s
(92.36%)
unplanned: track.exists(playlists)📈 view plot
🚷 view threshold
3.77 ops/s
(-6.46%)Baseline: 4.03 ops/s
3.47 ops/s
(91.99%)
zpg: all playlists📈 view plot
🚷 view threshold
5.38 ops/s
(-4.76%)Baseline: 5.65 ops/s
5.06 ops/s
(94.00%)
zql: all playlists📈 view plot
🚷 view threshold
7.10 ops/s
(-7.63%)Baseline: 7.69 ops/s
6.19 ops/s
(87.11%)
zql: edit for limited query, inside the bound📈 view plot
🚷 view threshold
202,222.52 ops/s
(-4.08%)Baseline: 210,816.51 ops/s
178,293.69 ops/s
(88.17%)
zql: edit for limited query, outside the bound📈 view plot
🚷 view threshold
211,292.20 ops/s
(-2.54%)Baseline: 216,798.24 ops/s
170,686.54 ops/s
(80.78%)
zql: push into limited query, inside the bound📈 view plot
🚷 view threshold
100,057.14 ops/s
(-7.12%)Baseline: 107,732.78 ops/s
90,583.38 ops/s
(90.53%)
zql: push into limited query, outside the bound📈 view plot
🚷 view threshold
342,291.05 ops/s
(-12.89%)Baseline: 392,946.84 ops/s
306,115.45 ops/s
(89.43%)
zql: push into unlimited query📈 view plot
🚷 view threshold
297,026.91 ops/s
(-8.92%)Baseline: 326,104.94 ops/s
268,061.71 ops/s
(90.25%)
zqlite: all playlists📈 view plot
🚷 view threshold
1.63 ops/s
(-8.06%)Baseline: 1.78 ops/s
1.45 ops/s
(88.86%)
zqlite: edit for limited query, inside the bound📈 view plot
🚷 view threshold
73,557.73 ops/s
(-2.71%)Baseline: 75,604.02 ops/s
60,306.57 ops/s
(81.99%)
zqlite: edit for limited query, outside the bound📈 view plot
🚷 view threshold
68,902.19 ops/s
(-8.85%)Baseline: 75,590.26 ops/s
57,795.40 ops/s
(83.88%)
zqlite: push into limited query, inside the bound📈 view plot
🚷 view threshold
3,763.88 ops/s
(-6.84%)Baseline: 4,040.45 ops/s
3,652.39 ops/s
(97.04%)
zqlite: push into limited query, outside the bound📈 view plot
🚷 view threshold
85,555.21 ops/s
(-2.33%)Baseline: 87,599.39 ops/s
76,075.70 ops/s
(88.92%)
zqlite: push into unlimited query📈 view plot
🚷 view threshold
114,917.33 ops/s
(-6.80%)Baseline: 123,308.09 ops/s
103,175.90 ops/s
(89.78%)
🐰 View full continuous benchmarking report in Bencher

@darkgnotic darkgnotic added this pull request to the merge queue Jan 16, 2026
Merged via the queue into main with commit 864088c Jan 16, 2026
18 checks passed
@darkgnotic darkgnotic deleted the darkgnotic/fix-unhandled-rejection branch January 16, 2026 22:17
@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🐰 Bencher Report

Branchdarkgnotic/fix-unhandled-rejection
Testbedself-hosted
Click to view all benchmark results
BenchmarkThroughputBenchmark Result
operations / second (ops/s)
(Result Δ%)
Lower Boundary
operations / second (ops/s)
(Limit %)
src/client/custom.bench.ts > big schema📈 view plot
🚷 view threshold
135,218.00 ops/s
(-11.70%)Baseline: 153,127.28 ops/s
-106,317.31 ops/s
(-78.63%)
src/client/zero.bench.ts > basics > All 1000 rows x 10 columns (numbers)📈 view plot
🚷 view threshold
2,321.54 ops/s
(-6.00%)Baseline: 2,469.70 ops/s
2,087.29 ops/s
(89.91%)
src/client/zero.bench.ts > pk compare > pk = N📈 view plot
🚷 view threshold
60,158.00 ops/s
(-6.20%)Baseline: 64,132.71 ops/s
54,209.14 ops/s
(90.11%)
src/client/zero.bench.ts > with filter > Lower rows 500 x 10 columns (numbers)📈 view plot
🚷 view threshold
3,549.29 ops/s
(-6.04%)Baseline: 3,777.27 ops/s
3,238.87 ops/s
(91.25%)
🐰 View full continuous benchmarking report in Bencher

darkgnotic added a commit that referenced this pull request Jan 16, 2026
User report:
*
https://discord.com/channels/830183651022471199/1461757924664938654/1461790264740810905
 
The code to initiate parallel fetching of config patches and row patches
left one Promise without a catch handler until it gets awaited later on.
If an exception happens before the `await`, Node crashes the server with
an unhandled rejection error.

The fix is to install a catch handler ahead of time. It is okay to be a
noop because the exception will be handled later when the promise is
awaited. (Technically, it may be dropped if the row patches throws an
error, but this is also okay).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants