-
- Unable to retrieve results as the provided value in your filter(s) doesn't match it's column
- data type.
+
+ One or more of your filters may have a value or operator that doesn't match the column's
+ data type. Try updating or removing the filter.
-
- Verify that your filter values are correct before applying the filters again.
-
-
- Error: {error.message}
-
-
-
diff --git a/apps/studio/components/grid/components/grid/GridError.utils.test.ts b/apps/studio/components/grid/components/grid/GridError.utils.test.ts
new file mode 100644
index 00000000000..5a1095dd782
--- /dev/null
+++ b/apps/studio/components/grid/components/grid/GridError.utils.test.ts
@@ -0,0 +1,87 @@
+import { describe, expect, test } from 'vitest'
+
+import { isFilterRelatedError } from './GridError.utils'
+
+describe('isFilterRelatedError', () => {
+ test('returns false for null or undefined', () => {
+ expect(isFilterRelatedError(null)).toBe(false)
+ expect(isFilterRelatedError(undefined)).toBe(false)
+ })
+
+ test('returns false for empty string', () => {
+ expect(isFilterRelatedError('')).toBe(false)
+ })
+
+ test('returns false for unrelated error messages', () => {
+ expect(isFilterRelatedError('connection refused')).toBe(false)
+ expect(isFilterRelatedError('permission denied for table users')).toBe(false)
+ expect(isFilterRelatedError('relation "users" does not exist')).toBe(false)
+ expect(isFilterRelatedError('Query cost exceeds threshold')).toBe(false)
+ })
+
+ test('detects invalid input syntax errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22P02: invalid input syntax for type inet: "192.168.3"'
+ )
+ ).toBe(true)
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22P02: invalid input syntax for type integer: "abc"'
+ )
+ ).toBe(true)
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22P02: invalid input syntax for type uuid: "not-a-uuid"'
+ )
+ ).toBe(true)
+ })
+
+ test('detects operator does not exist errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 42883: operator does not exist: text > integer'
+ )
+ ).toBe(true)
+ })
+
+ test('detects collation errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: could not determine which collation to use for string comparison'
+ )
+ ).toBe(true)
+ })
+
+ test('detects invalid enum value errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22P02: invalid input value for enum status: "badvalue"'
+ )
+ ).toBe(true)
+ })
+
+ test('detects malformed array literal errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22P02: malformed array literal: "not-an-array"'
+ )
+ ).toBe(true)
+ })
+
+ test('detects invalid byte sequence errors', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 22021: invalid byte sequence for encoding "UTF8"'
+ )
+ ).toBe(true)
+ })
+
+ test('detects syntax errors from invalid IS operator values', () => {
+ expect(
+ isFilterRelatedError(
+ 'Failed to run sql query: ERROR: 42601: syntax error at or near "sdfsdf"'
+ )
+ ).toBe(true)
+ })
+})
diff --git a/apps/studio/components/grid/components/grid/GridError.utils.ts b/apps/studio/components/grid/components/grid/GridError.utils.ts
new file mode 100644
index 00000000000..cc1331c74c9
--- /dev/null
+++ b/apps/studio/components/grid/components/grid/GridError.utils.ts
@@ -0,0 +1,14 @@
+const FILTER_ERROR_PATTERNS = [
+ 'invalid input syntax',
+ 'operator does not exist',
+ 'could not determine which collation',
+ 'invalid input value for enum',
+ 'malformed array literal',
+ 'invalid byte sequence',
+ 'syntax error',
+]
+
+export function isFilterRelatedError(errorMessage: string | undefined | null): boolean {
+ if (!errorMessage) return false
+ return FILTER_ERROR_PATTERNS.some((pattern) => errorMessage.includes(pattern))
+}
diff --git a/e2e/studio/features/filter-bar.spec.ts b/e2e/studio/features/filter-bar.spec.ts
index 09fc74545ae..86597c9e758 100644
--- a/e2e/studio/features/filter-bar.spec.ts
+++ b/e2e/studio/features/filter-bar.spec.ts
@@ -13,6 +13,7 @@ import {
} from '../utils/filter-bar-helpers.js'
import { test } from '../utils/test.js'
import { toUrl } from '../utils/to-url.js'
+import { createApiResponseWaiter } from '../utils/wait-for-response.js'
const tableNamePrefix = 'pw_filter_bar'
@@ -811,4 +812,50 @@ test.describe('Filter Bar', () => {
}
})
})
+
+ test.describe('Filter Error Feedback', () => {
+ test('invalid filter value shows friendly error and remove button clears filters', async ({
+ page,
+ ref,
+ }) => {
+ const tableName = `${tableNamePrefix}_err_fb`
+
+ await createTable(tableName, 'name', [{ name: 'Alice' }, { name: 'Bob' }])
+
+ try {
+ await setupFilterBarPage(page, ref, toUrl(`/project/${ref}/editor?schema=public`))
+ await navigateToTable(page, ref, tableName)
+
+ // Apply a filter using the 'is' operator with an invalid value
+ // 'is' only accepts null/not null/true/false, so 'badvalue' triggers a syntax error
+ await selectColumnFilter(page, 'name')
+ await selectOperatorByClick(page, 'name', 'is')
+
+ const valueInput = page.getByTestId('filter-value-name')
+ const rowsWaiter = createApiResponseWaiter(page, 'pg-meta', ref, 'query?key=table-rows-')
+ await valueInput.fill('badvalue')
+ await page.keyboard.press('Enter')
+ await rowsWaiter
+
+ // Should show the friendly filter error, not the scary general error
+ await expect(page.getByText('No results found — check your filter values')).toBeVisible({
+ timeout: 10000,
+ })
+ await expect(page.getByText("doesn't match the column's data type")).toBeVisible()
+
+ const removeButton = page.getByRole('button', { name: 'Remove filters' })
+ await expect(removeButton).toBeVisible()
+
+ // Clicking "Remove filters" should clear filters and restore data
+ await removeButton.click()
+
+ // Filter pill should be gone and data should be visible again
+ await expect(page.getByTestId('filter-condition-name')).not.toBeVisible({ timeout: 10000 })
+ await expect(page.getByRole('gridcell', { name: 'Alice' })).toBeVisible({ timeout: 10000 })
+ await expect(page.getByRole('gridcell', { name: 'Bob' })).toBeVisible()
+ } finally {
+ await dropTable(tableName)
+ }
+ })
+ })
})