Skip to content

Graph View layout broken for TB/RL/BT orientations when using TaskGroups (nodes spread horizontally) #61384

@rsilvestre

Description

@rsilvestre

Apache Airflow version

3.1.6

If "Other Airflow 3 version" selected, which one?

Also tested on 3.0.6 where the issue does NOT occur - this is a regression introduced between 3.0.6 and 3.1.x

What happened?

When using TaskGroups in a DAG and viewing the Graph View with any orientation other than Left-to-Right (LR), the graph layout is completely broken.
Affected orientations: Top-to-Bottom (TB), Right-to-Left (RL), Bottom-to-Top (BT)
Working orientation: Left-to-Right (LR) only
In the broken state:

Nodes spread horizontally instead of following the expected vertical alignment
TaskGroup boundaries overlap with other nodes
Text is truncated and unreadable
The overall graph structure becomes chaotic and hard to follow
Dependency lines cross over nodes incorrectly

This is a regression from Airflow 3.0.6 where all orientations rendered correctly.
See attached screenshots comparing the same DAG in 3.0.6 (correct) vs 3.1.6 (broken) using Bottom-to-Top orientation.

What you think should happen instead?

The Graph View should render nodes with proper vertical alignment for TB/RL/BT orientations, exactly as it did in Airflow 3.0.6:

Nodes should stack vertically (for TB/BT) or maintain proper alignment (for RL)
TaskGroup boundaries should contain their child nodes without overlapping other elements
Text should be fully readable without truncation
Dependency lines should follow clean paths between nodes

The behavior in 3.0.6 was correct - nodes were cleanly aligned and the graph was easy to read and navigate.

How to reproduce

  1. Create a DAG with TaskGroups containing multiple tasks
  2. Set the DAG orientation to anything other than 'LR' (e.g., 'TB', 'BT', or 'RL')
  3. Open the DAG in the Airflow UI and navigate to the Graph View
  4. Observe the broken layout

Minimal reproduction DAG:

from datetime import datetime
from airflow import DAG
from airflow.decorators import task, task_group

with DAG(
    dag_id="graph_layout_bug_reproduction",
    start_date=datetime(2024, 1, 1),
    schedule=None,
) as dag:

    @task
    def start_task():
        return "start"

    @task
    def prepare_extraction():
        return "prepared"

    @task_group(group_id="ingest_data")
    def ingest_data_group():
        @task
        def log_transition_success():
            return "success"

        @task
        def clear_cookies_and_info():
            return "cleared"

        @task
        def log_transition_clean():
            return "clean"

        @task
        def load_minivault_partition():
            return "partition"

        @task
        def load_minivault_file():
            return "file"

        @task
        def log_transition_minivault():
            return "minivault"

        @task
        def consolidate_cookies():
            return "consolidated"

        @task
        def log_transition_consolidate():
            return "consolidate_log"

        t1 = log_transition_success()
        t2 = clear_cookies_and_info()
        t3 = log_transition_clean()
        t4 = load_minivault_partition()
        t5 = load_minivault_file()
        t6 = log_transition_minivault()
        t7 = consolidate_cookies()
        t8 = log_transition_consolidate()

        t1 >> t2 >> t3 >> [t4, t5] >> t6 >> t7 >> t8

    @task_group(group_id="batch_job")
    def batch_job_group():
        @task
        def wait_for_batch_job():
            return "waiting"

        @task
        def batch_submit():
            return "submitted"

        t_wait = wait_for_batch_job()
        t_submit = batch_submit()
        t_wait >> t_submit

    @task
    def extraction_task():
        return "extracted"

    @task
    def end_task():
        return "end"

    start = start_task()
    prepare = prepare_extraction()
    ingest = ingest_data_group()
    batch = batch_job_group()
    extract = extraction_task()
    end = end_task()

    start >> prepare >> ingest >> batch >> extract >> end

will looks like this in BT :

Image

Steps:

  1. Deploy this DAG to Airflow 3.1.6
  2. Navigate to the DAG page
  3. Click on "Graph" view
  4. Observe the broken layout (nodes spreading horizontally, overlapping, etc.)
  5. Change orientation="BT" to orientation="LR" and redeploy
  6. Observe that LR orientation renders correctly

Example:

Version 3.0.6

Image

Version 3.1.6

Image

Operating System

Amazon Linux 2023 (AL2023)

Versions of Apache Airflow Providers

requirements.txt

--constraint "https://raw.githubusercontent.com/apache/airflow/constraints-3.1.6/constraints-3.12.txt"

# AWS SDKs (versions managed by Airflow constraints)
aiobotocore
boto3
boto3-stubs[essential]
botocore

# Core dependencies (versions managed by Airflow constraints where applicable)
cached-property
cron-descriptor
graphviz
ndg-httpsclient
pendulum
psycopg2-binary
pyasn1
pyOpenSSL
pyyaml
pytz
redis
smart_open[s3]
sqlalchemy

# Apache Airflow with providers
apache-airflow[s3,crypto,celery,postgres,elasticsearch,statsd,ssh,slack,http,amazon]==3.1.6

Deployment

Other Docker-based deployment

Deployment details

Using amazon-mwaa-docker-images (https://github.com/aws/amazon-mwaa-docker-images) for local development, but the bug is in upstream Airflow UI - MWAA does not modify the graph rendering component.
Tested with:

Docker version 24.0.x
docker-compose version 2.x
Airflow 3.0.6 (working) vs 3.1.6 (broken)

Anything else?

Frequency: This problem occurs 100% of the time when:

Using any orientation other than LR (Left-to-Right)
Having TaskGroups in the DAG

Related issues:

#56250 (AF3 UI issues)
#51538 (Inconsistent Task Ordering between grid view and graph view)
#35301 (New Graph UI struggles with nested task groups)

Root cause hypothesis:
The React Flow migration and subsequent UI restructuring between 3.0.x and 3.1.x likely introduced changes to the useGraphLayout hook that don't properly handle non-LR orientations when TaskGroups are present.

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:UIRelated to UI/UX. For Frontend Developers.area:corekind:bugThis is a clearly a bugneeds-triagelabel for new issues that we didn't triage yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions