edsu opened a new issue, #72344: URL: https://github.com/apache/airflow/issues/72344
### Under which category would you file this issue? Airflow Core ### Apache Airflow version 3.3.1 ### What happened and how to reproduce it? When Airflow is served under a path prefix (`[api] base_url = http://host/workflows`), the UI issues its first API request to the **origin root** instead of the configured prefix: ``` GET /api/v2/version <- actual GET /workflows/api/v2/version <- expected ``` Every later request is correctly prefixed; only the startup one is wrong. On a deployment where something else is mounted at `/api/`, that request reaches the wrong service. In our case a reverse proxy routes `/api/` to a different application, which answers `401`. The UI treats the 401 as "session expired" and redirects to login; login succeeds, the app reloads, the same request 401s again. The result is an **infinite login redirect loop** — the UI renders its frame, data loads correctly, then it bounces back to login, about once per second. Even where `/api/` is not otherwise routed, the request is still sent to the wrong path. This problem is not present in 3.2.0. ### Root cause `OpenAPI.BASE` is assigned as a module side effect in `queryClient.ts`: ```ts // airflow-core/src/airflow/ui/src/queryClient.ts import i18n from "src/i18n/config"; // line 23 ... OpenAPI.BASE = document.querySelector("head>base")?.getAttribute("href") ?? ""; // line 27 ``` But `queryClient.ts` **imports** `src/i18n/config`, and that module requests the version at module scope: ```ts // airflow-core/src/airflow/ui/src/i18n/config.ts export const resolveI18nVersion = (): Promise<string> => VersionService.getVersion() .then((data) => data.version) .catch(() => Date.now().toString()); void resolveI18nVersion().then(initI18n); // line 163 ``` ES module evaluation runs a dependency to completion before the importing module's body, so `i18n/config.ts` always issues `getVersion()` **before** line 27 assigns `OpenAPI.BASE`. The generated client builds the URL as `config.BASE + path` with `BASE` still `""`. A visible side effect: because the request fails, `resolveI18nVersion` falls back to `Date.now()`, so translation files are fetched with a timestamp cache buster (`?v=1787955819428`) rather than the version. The cache-busting feature the call exists for is therefore also defeated on these deployments. ### Regression Introduced by #65720 ("i18n translation files served stale after Airflow upgrade due to browser cache"), which added the `getVersion()` call to `i18n/config.ts`. That commit is not in 3.2.0 and is in 3.3.0+. In 3.2.0 `i18n/config.ts` neither imports `VersionService` nor calls the API, so the first request happened after `OpenAPI.BASE` was set. Note there are now three separate `<base href>` lookups in the UI (`queryClient.ts`, `i18n/config.ts`, `utils/links.ts`), which is what let these drift apart. ### How to reproduce Unit test (fails on `main`): ```ts // airflow-core/src/airflow/ui/src/queryClient.test.ts const BASE_HREF = "/workflows/"; vi.resetModules(); document.head.innerHTML = `<base href="${BASE_HREF}" />`; const requested: Array<string> = []; vi.spyOn(axios, "request").mockImplementation(async (config) => { requested.push(String(config.url)); return { config, data: { git_version: null, version: "3.3.1" }, headers: {}, status: 200, statusText: "OK" }; }); await import("src/queryClient"); await vi.waitFor(() => expect(requested.length).toBeGreaterThan(0)); expect(requested.filter((url) => !url.startsWith(BASE_HREF))).toEqual([]); ``` ``` AssertionError: expected [ '/api/v2/version' ] to deeply equal [] ``` ### What you think should happen instead? All API requests, including any issued during module initialization, resolve against `<base href>` so that a prefix deployment never sends requests to the origin root. ### Operating System macOS 26.6.2 ### Deployment Docker-Compose ### Apache Airflow Provider(s) _No response_ ### Versions of Apache Airflow Providers _No response_ ### Official Helm Chart version Not Applicable ### Kubernetes Version _No response_ ### Helm Chart configuration _No response_ ### Docker Image customizations https://github.com/blue-core-lod/bluecore-workflows/blob/upgrade-airflow-3.3.1/Dockerfile ### Anything else? _No response_ ### Are you willing to submit PR? - [x] Yes I am willing to submit a PR! ### Code of Conduct - [x] I agree to follow this project's [Code of Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
