This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new c34d2c36f2a [v3-1-test] Add 404 handling for non-existent Dag (#61131)
(#61225)
c34d2c36f2a is described below
commit c34d2c36f2a315bb6546a6de8176d2b24bebe18b
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Jan 29 15:52:56 2026 -0500
[v3-1-test] Add 404 handling for non-existent Dag (#61131) (#61225)
(cherry picked from commit 4b34c4206e12b419d28a6d365e9973dc94979d0c)
Co-authored-by: Yeonguk Choo <[email protected]>
---
.../src/airflow/ui/public/i18n/locales/en/dag.json | 6 ++
airflow-core/src/airflow/ui/src/pages/Dag/Dag.tsx | 7 +++
.../src/airflow/ui/src/pages/Dag/DagNotFound.tsx | 70 ++++++++++++++++++++++
3 files changed, 83 insertions(+)
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
b/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
index 8085fcb942d..8241c26ccae 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
@@ -73,6 +73,12 @@
"navigation": "Navigation: Shift+{{arrow}}",
"toggleGroup": "Toggle group: Space"
},
+ "notFound": {
+ "back": "Go Back",
+ "backToDags": "Back to Dags",
+ "message": "The Dag \"{{dagId}}\" does not exist.",
+ "title": "Dag Not Found"
+ },
"overview": {
"buttons": {
"failedRun_one": "Failed Run",
diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Dag.tsx
b/airflow-core/src/airflow/ui/src/pages/Dag/Dag.tsx
index 3ba287faffd..4ea3fa73d55 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Dag.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Dag.tsx
@@ -26,6 +26,7 @@ import { RiArrowGoBackFill } from "react-icons/ri";
import { useParams } from "react-router-dom";
import { useDagServiceGetDagDetails, useDagServiceGetLatestRunInfo } from
"openapi/queries";
+import { ApiError } from "openapi/requests/core/ApiError";
import { TaskIcon } from "src/assets/TaskIcon";
import { usePluginTabs } from "src/hooks/usePluginTabs";
import { useRequiredActionTabs } from "src/hooks/useRequiredActionTabs";
@@ -33,6 +34,7 @@ import { DetailsLayout } from
"src/layouts/Details/DetailsLayout";
import { useRefreshOnNewDagRuns } from "src/queries/useRefreshOnNewDagRuns";
import { isStatePending, useAutoRefresh } from "src/utils";
+import { DagNotFound } from "./DagNotFound";
import { Header } from "./Header";
export const Dag = () => {
@@ -103,6 +105,11 @@ export const Dag = () => {
return true;
});
+ // Handle 404 error when Dag is not found
+ if (error instanceof ApiError && error.status === 404) {
+ return <DagNotFound dagId={dagId} />;
+ }
+
return (
<ReactFlowProvider>
<DetailsLayout error={error ?? runsError} isLoading={isLoading ||
isLoadingRuns} tabs={displayTabs}>
diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/DagNotFound.tsx
b/airflow-core/src/airflow/ui/src/pages/Dag/DagNotFound.tsx
new file mode 100644
index 00000000000..0a667e8ef63
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/DagNotFound.tsx
@@ -0,0 +1,70 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { Box, Button, Container, Heading, HStack, Text, VStack } from
"@chakra-ui/react";
+import { useTranslation } from "react-i18next";
+import { useNavigate } from "react-router-dom";
+
+import { AirflowPin } from "src/assets/AirflowPin";
+
+type DagNotFoundProps = {
+ readonly dagId: string;
+};
+
+export const DagNotFound = ({ dagId }: DagNotFoundProps) => {
+ const navigate = useNavigate();
+ const { t: translate } = useTranslation("dag");
+
+ return (
+ <Box alignItems="center" display="flex" justifyContent="center" pt={36}
px={4}>
+ <Container maxW="lg">
+ <VStack gap={8} textAlign="center">
+ <AirflowPin height="50px" width="50px" />
+
+ <VStack gap={4}>
+ <Heading>404</Heading>
+ <Text fontSize="lg">{translate("notFound.title")}</Text>
+ <Text color="fg.muted">{translate("notFound.message", { dagId
})}</Text>
+ </VStack>
+
+ <HStack gap={4}>
+ <Button
+ colorPalette="brand"
+ onClick={() => {
+ void Promise.resolve(navigate(-1));
+ }}
+ size="lg"
+ >
+ {translate("notFound.back")}
+ </Button>
+ <Button
+ colorPalette="brand"
+ onClick={() => {
+ void Promise.resolve(navigate("/dags"));
+ }}
+ size="lg"
+ variant="outline"
+ >
+ {translate("notFound.backToDags")}
+ </Button>
+ </HStack>
+ </VStack>
+ </Container>
+ </Box>
+ );
+};