Skip to content

Log errors from watched queries - #1068

Open
giaBaoJS wants to merge 1 commit into
powersync-ja:mainfrom
giaBaoJS:log-watched-query-errors
Open

Log errors from watched queries#1068
giaBaoJS wants to merge 1 commit into
powersync-ja:mainfrom
giaBaoJS:log-watched-query-errors

Conversation

@giaBaoJS

Copy link
Copy Markdown

Overview

useQuery gives no signal at all when the underlying query fails. The error is stored on the returned error field and dispatched to onError listeners, but nothing is inspected by default, so an invalid query looks like a query that simply never returns rows — the console stays empty, as reported in #834.

The deprecated callback API does not have this problem: watchWithCallback defaults onError to a logger call (packages/shared-internals/src/client/BasePowerSyncDatabase.ts:659), so the WatchedQuery/useQuery path lost that behaviour rather than never having it.

Changes

Errors are now logged with the database's logger, matching the existing 'Watched query error handler threw an Error' log in the same file.

  • AbstractQueryProcessor.updateState logs whenever an error is set on the state. This is the single funnel every watched-query failure passes through, which matters because the two paths are separate:

    • table resolution failing in linkQuery (caught by runWithReporting) — this is what a missing table hits, since resolveTables runs EXPLAIN <sql>;
    • the query itself failing on re-execution (caught inside the onChange callbacks of OnChangeQueryProcessor and DifferentialQueryProcessor) — this is where runtime failures such as SQLite I/O errors surface.

    error: null is used to clear a previous error, so only truthy errors are logged.

  • useSingleQuery logs the same way for the runQueryOnce path, which does not go through a query processor.

  • watchWithCallback's default onError no longer logs. The watched query now does that, so keeping it would print the same error twice for every existing consumer of that API. Consumers passing their own onError are unaffected, other than now also getting the log.

On log noise

Queries that are expected to fail will now produce output where they previously produced none. That seemed like the right trade-off given the issue: the error is only emitted once per failure, at error level, and applications that want to handle failures themselves can supply a logger with a higher minLevel or their own implementation when constructing the database.

Tests

Three tests in packages/react/tests/useQuery.test.tsx (run in both normal and StrictMode), one per failure path: table resolution, query execution, and runQueryOnce. Each asserts that the logged record carries the real underlying error, and that it reaches console.error through the default logger — the console being empty is what the issue actually describes.

All six fail on current main with expected 0 to be greater than 0.

Fixes #834.

Errors raised while resolving or executing a watched query were only
reported on the query state and to error listeners. Neither is inspected
by default, so `useQuery` appeared to silently do nothing when the query
was invalid.

Log the error with the database's logger from `AbstractQueryProcessor`,
which covers both the table resolution and query execution paths, and do
the same for the `runQueryOnce` path in `useSingleQuery`.

The default `onError` handler of `watchWithCallback` logged the error
itself. That is now handled by the watched query, so the default handler
no longer logs to avoid emitting the same error twice.
@changeset-bot

changeset-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 41fca45

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

This PR includes changesets to release 9 packages
Name Type
@powersync/shared-internals Patch
@powersync/react Patch
@powersync/adapter-sql-js Patch
@powersync/capacitor Patch
@powersync/node Patch
@powersync/react-native Patch
@powersync/web Patch
@powersync/diagnostics-app Patch
@powersync/tanstack-react-query 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

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.

useQuery swallows underlying Kysely errors

1 participant