This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new b5b39ccd8f0 Include the JSON parse-error message in the Variable form 
warning (#71780)
b5b39ccd8f0 is described below

commit b5b39ccd8f044b633e6b0d7db9100d2ad1e09661
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Fri Aug 21 16:44:10 2026 +0200

    Include the JSON parse-error message in the Variable form warning (#71780)
    
    The Variables form warns "Invalid JSON" the moment the value looks
    like it might be JSON but doesn't parse. That warning tells the user
    something's wrong but not where, so a typo halfway through a large
    value is still a hunt.
    
    The browser's SyntaxError from JSON.parse already carries the position
    ("Unexpected token ',' at position 42 (line 3 column 12)" on V8,
    similar on Firefox / Safari). Surface it alongside the localized label
    so users can jump straight to the character that broke the parse.
    
    The parser message is emitted by the JS engine and is only ever in
    English — mixing it with a localized label is a compromise, but the
    position info is more valuable than perfect localization here, and no
    browser offers a localized JSON parse error to begin with.
    
    closes: #68262
---
 .../Variables/ManageVariable/VariableForm.test.tsx |  6 +++---
 .../Variables/ManageVariable/VariableForm.tsx      | 22 ++++++++++++----------
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.test.tsx
 
b/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.test.tsx
index 70d45765cb9..70b4e0b09e9 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.test.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.test.tsx
@@ -55,7 +55,7 @@ describe("VariableForm", () => {
 
     fireEvent.change(screen.getByLabelText(/value/iu), { target: { value: 
'{"enabled": true,' } });
 
-    await waitFor(() => 
expect(screen.getByText("variables.form.invalidJson")).toBeInTheDocument());
+    await waitFor(() => 
expect(screen.getByText(/variables\.form\.invalidJson/u)).toBeInTheDocument());
     expect(screen.getByRole("button", { name: /save/iu })).toBeEnabled();
 
     fireEvent.click(screen.getByRole("button", { name: /save/iu }));
@@ -73,7 +73,7 @@ describe("VariableForm", () => {
 
     fireEvent.change(screen.getByLabelText(/value/iu), { target: { value: 
"[DRAFT] plain string value" } });
 
-    await waitFor(() => 
expect(screen.getByText("variables.form.invalidJson")).toBeInTheDocument());
+    await waitFor(() => 
expect(screen.getByText(/variables\.form\.invalidJson/u)).toBeInTheDocument());
     expect(screen.getByRole("button", { name: /save/iu })).toBeEnabled();
 
     fireEvent.click(screen.getByRole("button", { name: /save/iu }));
@@ -91,7 +91,7 @@ describe("VariableForm", () => {
 
     fireEvent.change(screen.getByLabelText(/value/iu), { target: { value: "{{ 
var.value.x }}" } });
 
-    await waitFor(() => 
expect(screen.getByText("variables.form.invalidJson")).toBeInTheDocument());
+    await waitFor(() => 
expect(screen.getByText(/variables\.form\.invalidJson/u)).toBeInTheDocument());
     expect(screen.getByRole("button", { name: /save/iu })).toBeEnabled();
 
     fireEvent.click(screen.getByRole("button", { name: /save/iu }));
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.tsx
 
b/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.tsx
index d555f641a99..21750010e5b 100644
--- 
a/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.tsx
+++ 
b/airflow-core/src/airflow/ui/src/pages/Variables/ManageVariable/VariableForm.tsx
@@ -33,14 +33,14 @@ export type VariableBody = {
   value: string;
 };
 
-const isJsonString = (string: string) => {
+const getJsonParseError = (string: string): string | undefined => {
   try {
     JSON.parse(string);
-  } catch {
-    return false;
-  }
 
-  return true;
+    return undefined;
+  } catch (error) {
+    return error instanceof Error ? error.message : String(error);
+  }
 };
 
 type VariableFormProps = {
@@ -97,8 +97,10 @@ const VariableForm = ({ error, initialVariable, isPending, 
manageMutate, setErro
         control={control}
         name="value"
         render={({ field, fieldState }) => {
-          const showJsonWarning =
-            field.value.startsWith("{") || field.value.startsWith("[") ? 
!isJsonString(field.value) : false;
+          const jsonParseError =
+            field.value.startsWith("{") || field.value.startsWith("[")
+              ? getJsonParseError(field.value)
+              : undefined;
 
           return (
             <Field.Root invalid={Boolean(fieldState.error)} mt={4} required>
@@ -106,11 +108,11 @@ const VariableForm = ({ error, initialVariable, 
isPending, manageMutate, setErro
                 {translate("columns.value")} <Field.RequiredIndicator />
               </Field.Label>
               <Textarea {...field} size="sm" />
-              {showJsonWarning ? (
+              {jsonParseError === undefined ? undefined : (
                 <Alert mt={2} status="warning">
-                  {translate("variables.form.invalidJson")}
+                  {translate("variables.form.invalidJson")}: {jsonParseError}
                 </Alert>
-              ) : undefined}
+              )}
               {fieldState.error ? 
<Field.ErrorText>{fieldState.error.message}</Field.ErrorText> : undefined}
             </Field.Root>
           );

Reply via email to