Skip to content

Conversation

@KyleAMathews
Copy link
Collaborator

@KyleAMathews KyleAMathews commented Jan 12, 2026

Summary

Improves the DuplicateKeySyncError message when using .distinct() with a custom getKey. Users now get actionable guidance instead of a confusing generic error.

Root Cause

When combining .distinct() with a custom getKey, users can unknowingly create a key collision:

  • .distinct() deduplicates by the entire selected object
  • But getKey extracts only a subset of fields for the key

This means two rows that are "distinct" (different in some fields) can still produce the same key, triggering a DuplicateKeySyncError with no indication of why.

Approach

Added a hasDistinct flag to LiveQueryInternalUtils and propagated it through to the error constructor. When both hasCustomGetKey and hasDistinct are true, the error message now explains:

  1. Why the collision happened (distinct vs key semantics mismatch)
  2. Three concrete fixes the user can apply
// New error message excerpt:
"The .distinct() operator deduplicates by the ENTIRE selected object, 
but your custom getKey extracts only a subset of fields..."

Key Invariants

  • The hasDistinct flag accurately reflects whether the query uses .distinct()
  • The specialized error only triggers when both hasCustomGetKey and hasDistinct are true
  • Existing hasJoins error path remains unchanged (checked second via else if)

Non-goals

  • Not changing the behavior of .distinct() or getKey—just improving the error message
  • Not adding runtime validation to prevent this combination

Verification

pnpm test --filter @tanstack/db

Files Changed

File Change
packages/db/src/errors.ts Add hasDistinct option and new error message branch
packages/db/src/collection/sync.ts Pass hasDistinct to error constructor
packages/db/src/query/live/collection-config-builder.ts Set hasDistinct from query
packages/db/src/query/live/internal.ts Add hasDistinct to type definition

🤖 Generated with Claude Code

When using `.distinct()` with a custom `getKey`, the error message now
explains that `.distinct()` deduplicates by the entire selected object,
not by the key field. This helps users understand they should either:
1. Ensure SELECT only includes fields that make up the key
2. Use .groupBy() instead of .distinct() for explicit control
3. Remove the custom getKey to use default key behavior

This addresses a production bug where users were getting confusing
duplicate key errors when combining these features.
@changeset-bot
Copy link

changeset-bot bot commented Jan 12, 2026

🦋 Changeset detected

Latest commit: bb6b8c3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@tanstack/db Patch
@tanstack/angular-db Patch
@tanstack/electric-db-collection Patch
@tanstack/offline-transactions Patch
@tanstack/powersync-db-collection Patch
@tanstack/query-db-collection Patch
@tanstack/react-db Patch
@tanstack/rxdb-db-collection Patch
@tanstack/solid-db Patch
@tanstack/svelte-db Patch
@tanstack/trailbase-db-collection Patch
@tanstack/vue-db Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 12, 2026

More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1119

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1119

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1119

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1119

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1119

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1119

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1119

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1119

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1119

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1119

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1119

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1119

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1119

commit: bb6b8c3

@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

Size Change: +235 B (+0.26%)

Total Size: 90.8 kB

Filename Size Change
./packages/db/dist/esm/collection/sync.js 2.4 kB +15 B (+0.63%)
./packages/db/dist/esm/errors.js 4.7 kB +204 B (+4.54%) 🔍
./packages/db/dist/esm/query/live/collection-config-builder.js 5.42 kB +16 B (+0.3%)
ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection/change-events.js 1.39 kB
./packages/db/dist/esm/collection/changes.js 1.19 kB
./packages/db/dist/esm/collection/events.js 388 B
./packages/db/dist/esm/collection/index.js 3.32 kB
./packages/db/dist/esm/collection/indexes.js 1.1 kB
./packages/db/dist/esm/collection/lifecycle.js 1.67 kB
./packages/db/dist/esm/collection/mutations.js 2.34 kB
./packages/db/dist/esm/collection/state.js 3.46 kB
./packages/db/dist/esm/collection/subscription.js 3.62 kB
./packages/db/dist/esm/deferred.js 207 B
./packages/db/dist/esm/event-emitter.js 748 B
./packages/db/dist/esm/index.js 2.69 kB
./packages/db/dist/esm/indexes/auto-index.js 742 B
./packages/db/dist/esm/indexes/base-index.js 766 B
./packages/db/dist/esm/indexes/btree-index.js 1.93 kB
./packages/db/dist/esm/indexes/lazy-index.js 1.1 kB
./packages/db/dist/esm/indexes/reverse-index.js 513 B
./packages/db/dist/esm/local-only.js 837 B
./packages/db/dist/esm/local-storage.js 2.1 kB
./packages/db/dist/esm/optimistic-action.js 359 B
./packages/db/dist/esm/paced-mutations.js 496 B
./packages/db/dist/esm/proxy.js 3.75 kB
./packages/db/dist/esm/query/builder/functions.js 733 B
./packages/db/dist/esm/query/builder/index.js 4.08 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 1.05 kB
./packages/db/dist/esm/query/compiler/evaluators.js 1.42 kB
./packages/db/dist/esm/query/compiler/expressions.js 430 B
./packages/db/dist/esm/query/compiler/group-by.js 1.87 kB
./packages/db/dist/esm/query/compiler/index.js 1.96 kB
./packages/db/dist/esm/query/compiler/joins.js 2 kB
./packages/db/dist/esm/query/compiler/order-by.js 1.45 kB
./packages/db/dist/esm/query/compiler/select.js 1.06 kB
./packages/db/dist/esm/query/expression-helpers.js 1.43 kB
./packages/db/dist/esm/query/ir.js 673 B
./packages/db/dist/esm/query/live-query-collection.js 360 B
./packages/db/dist/esm/query/live/collection-registry.js 264 B
./packages/db/dist/esm/query/live/collection-subscriber.js 1.93 kB
./packages/db/dist/esm/query/live/internal.js 145 B
./packages/db/dist/esm/query/optimizer.js 2.56 kB
./packages/db/dist/esm/query/predicate-utils.js 2.97 kB
./packages/db/dist/esm/query/subset-dedupe.js 921 B
./packages/db/dist/esm/scheduler.js 1.3 kB
./packages/db/dist/esm/SortedMap.js 1.3 kB
./packages/db/dist/esm/strategies/debounceStrategy.js 247 B
./packages/db/dist/esm/strategies/queueStrategy.js 428 B
./packages/db/dist/esm/strategies/throttleStrategy.js 246 B
./packages/db/dist/esm/transactions.js 2.9 kB
./packages/db/dist/esm/utils.js 924 B
./packages/db/dist/esm/utils/browser-polyfills.js 304 B
./packages/db/dist/esm/utils/btree.js 5.61 kB
./packages/db/dist/esm/utils/comparison.js 852 B
./packages/db/dist/esm/utils/cursor.js 457 B
./packages/db/dist/esm/utils/index-optimization.js 1.51 kB
./packages/db/dist/esm/utils/type-guards.js 157 B

compressed-size-action::db-package-size

@github-actions
Copy link
Contributor

github-actions bot commented Jan 12, 2026

Size Change: 0 B

Total Size: 3.47 kB

ℹ️ View Unchanged
Filename Size
./packages/react-db/dist/esm/index.js 225 B
./packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.17 kB
./packages/react-db/dist/esm/useLiveQuery.js 1.12 kB
./packages/react-db/dist/esm/useLiveSuspenseQuery.js 559 B
./packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Ready for review

Development

Successfully merging this pull request may close these issues.

4 participants