diff --git a/.changeset/tame-otters-relax.md b/.changeset/tame-otters-relax.md
new file mode 100644
index 00000000000..1f5768de41e
--- /dev/null
+++ b/.changeset/tame-otters-relax.md
@@ -0,0 +1,5 @@
+---
+'@tanstack/preact-query': patch
+---
+
+fix(preact-query): propagate falsy errors to the error boundary
diff --git a/packages/preact-query/src/__tests__/useQueries.test.tsx b/packages/preact-query/src/__tests__/useQueries.test.tsx
index ccb3b3a34f4..b4ee5e69869 100644
--- a/packages/preact-query/src/__tests__/useQueries.test.tsx
+++ b/packages/preact-query/src/__tests__/useQueries.test.tsx
@@ -246,6 +246,43 @@ describe('useQueries', () => {
consoleMock.mockRestore()
})
+ it("should throw error if in one of queries' queryFn rejects with a falsy error and throwOnError is in use", async () => {
+ const consoleMock = vi
+ .spyOn(console, 'error')
+ .mockImplementation(() => undefined)
+ const key = queryKey()
+
+ function Page() {
+ useQueries({
+ queries: [
+ {
+ queryKey: key,
+ // Preact's error path dereferences the thrown value (`if (e.then)`), so a
+ // literal `undefined` error crashes the framework. `0` is just an arbitrary
+ // falsy value that's safe to dereference (`(0).then` is `undefined`, not a
+ // crash) — any falsy primitive other than `null`/`undefined` would do.
+ queryFn: () => Promise.reject(0),
+ retry: false,
+ throwOnError: true,
+ },
+ ],
+ })
+
+ return null
+ }
+
+ const rendered = renderWithClient(
+ queryClient,
+ error boundary
}>
+
+ ,
+ )
+
+ await vi.advanceTimersByTimeAsync(0)
+ expect(rendered.getByText('error boundary')).toBeInTheDocument()
+ consoleMock.mockRestore()
+ })
+
it('should use provided custom queryClient', async () => {
const key = queryKey()
const queryFn = async () => {
diff --git a/packages/preact-query/src/__tests__/useQuery.test.tsx b/packages/preact-query/src/__tests__/useQuery.test.tsx
index 52c92ab5243..edfeb71ad83 100644
--- a/packages/preact-query/src/__tests__/useQuery.test.tsx
+++ b/packages/preact-query/src/__tests__/useQuery.test.tsx
@@ -2781,6 +2781,39 @@ describe('useQuery', () => {
consoleMock.mockRestore()
})
+ it('should throw error if queryFn rejects with a falsy error and throwOnError is in use', async () => {
+ const consoleMock = vi
+ .spyOn(console, 'error')
+ .mockImplementation(() => undefined)
+ const key = queryKey()
+
+ function Page() {
+ const { status } = useQuery({
+ queryKey: key,
+ // Preact's error path dereferences the thrown value (`if (e.then)`), so a
+ // literal `undefined` error crashes the framework. `0` is just an arbitrary
+ // falsy value that's safe to dereference (`(0).then` is `undefined`, not a
+ // crash) — any falsy primitive other than `null`/`undefined` would do.
+ queryFn: () => Promise.reject(0),
+ retry: false,
+ throwOnError: true,
+ })
+
+ return
{status}
+ }
+
+ const rendered = renderWithClient(
+ queryClient,
+ error boundary
}>
+
+ ,
+ )
+
+ await vi.advanceTimersByTimeAsync(0)
+ expect(rendered.getByText('error boundary')).toBeInTheDocument()
+ consoleMock.mockRestore()
+ })
+
it('should update with data if we observe no properties and throwOnError', async () => {
const key = queryKey()
diff --git a/packages/preact-query/src/__tests__/useSuspenseQueries.test.tsx b/packages/preact-query/src/__tests__/useSuspenseQueries.test.tsx
index 3bb46eacc05..b5b7b0b754c 100644
--- a/packages/preact-query/src/__tests__/useSuspenseQueries.test.tsx
+++ b/packages/preact-query/src/__tests__/useSuspenseQueries.test.tsx
@@ -523,6 +523,46 @@ describe('useSuspenseQueries', () => {
expect(rendered.getByText('Data 1')).toBeInTheDocument()
})
+ it('should throw error when a queryFn rejects with a falsy error', async () => {
+ const consoleMock = vi
+ .spyOn(console, 'error')
+ .mockImplementation(() => undefined)
+ const key = queryKey()
+
+ function Page() {
+ const [query] = useSuspenseQueries({
+ queries: [
+ {
+ queryKey: key,
+ // Preact's error path dereferences the thrown value (`if (e.then)`), so a
+ // literal `undefined` error crashes the framework. `0` is just an arbitrary
+ // falsy value that's safe to dereference (`(0).then` is `undefined`, not a
+ // crash) — any falsy primitive other than `null`/`undefined` would do.
+ queryFn: () => sleep(10).then(() => Promise.reject(0)),
+ retry: false,
+ },
+ ],
+ })
+
+ return data: {String(query.data)}
+ }
+
+ const rendered = renderWithClient(
+ queryClient,
+ error boundary
}>
+
+
+
+ ,
+ )
+
+ expect(rendered.getByText('loading')).toBeInTheDocument()
+
+ await vi.advanceTimersByTimeAsync(10)
+ expect(rendered.getByText('error boundary')).toBeInTheDocument()
+ consoleMock.mockRestore()
+ })
+
it('should throw error when queryKey changes and new query fails', async () => {
const consoleMock = vi
.spyOn(console, 'error')
diff --git a/packages/preact-query/src/useQueries.ts b/packages/preact-query/src/useQueries.ts
index 39a3d043169..b0ed8b0b806 100644
--- a/packages/preact-query/src/useQueries.ts
+++ b/packages/preact-query/src/useQueries.ts
@@ -402,7 +402,7 @@ export function useQueries<
},
)
- if (firstSingleResultWhichShouldThrow?.error) {
+ if (firstSingleResultWhichShouldThrow) {
throw firstSingleResultWhichShouldThrow.error
}