From 3e26f0218f6477a61bd328bf1714fb4dcee2a11a Mon Sep 17 00:00:00 2001 From: Enzo Martellucci Date: Wed, 6 May 2026 12:32:10 +0200 Subject: [PATCH] fix(database): retry blur validation after a transient request failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the validate_parameters request failed without a structured error body (e.g. network drop), getValidation returned an empty object that the caller could not distinguish from "validation passed" — and the blur dedup cache was already updated, so the same form state would never revalidate until the user changed a field. Have getValidation return null on unexpected failure and only update the snapshot cache after a usable response. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/features/databases/DatabaseModal/index.tsx | 14 ++++++++++---- superset-frontend/src/views/CRUD/hooks.ts | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/superset-frontend/src/features/databases/DatabaseModal/index.tsx b/superset-frontend/src/features/databases/DatabaseModal/index.tsx index 8474cde2af6..bd9a26084af 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/index.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/index.tsx @@ -823,13 +823,19 @@ const DatabaseModal: FunctionComponent = ({ [onChange, handleClearValidationErrors], ); - const getBlurValidation = useCallback(() => { + const getBlurValidation = useCallback(async () => { const currentDbSnapshot = JSON.stringify(db); if (currentDbSnapshot === lastValidatedDbSnapshotRef.current) { - return Promise.resolve([]); + return []; } - lastValidatedDbSnapshotRef.current = currentDbSnapshot; - return getValidation(db); + const result = await getValidation(db); + // Only cache after a request that produced a usable response. ``null`` + // signals an unexpected/network failure, in which case we leave the + // snapshot untouched so the next blur retries. + if (result !== null) { + lastValidatedDbSnapshotRef.current = currentDbSnapshot; + } + return result; }, [db, getValidation]); const onClose = () => { diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index b7dae7a1e4f..4cb9e9f9c97 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -909,7 +909,7 @@ export function useDatabaseValidation() { setIsValidating(false); setHasValidated(true); } - return {}; + return null; } }, [setValidationErrors],