Skip to content

Notifiers when runing airflow dags locally though tests #64649

Description

@johnhoran

Apache Airflow version

3.1.7

What happened and how to reproduce it?

I am trying to port a Notifier to airflow 3 and ran into an issue when trying to run the code though airflow dags test. I reduced my dag down to

import logging
from datetime import datetime

from airflow import DAG
from airflow.sdk import BaseNotifier, task

class MyNotifier(BaseNotifier):
    log = logging.getLogger("MyNotifier")

    def notify(self, *args) -> None:
        self.log.info("Sending a really lovely message")

@task
def failing_task():
    """This task will intentionally fail."""
    raise Exception("This DAG is designed to fail!")

with DAG(
    dag_id="bad_dag",
    start_date=datetime(2024, 1, 1),
    schedule=None,
    catchup=False,
    tags=["test", "failing"],
    on_failure_callback=MyNotifier(),
) as dag:
    fail_task = failing_task()

And then when I run airflow dags test bad_dag 2025-10-03T08:00:00, the task fails as expected, but then an error is thrown

[2026-04-02T21:35:01.741165Z] {dagrun.py:1453} ERROR - Callback failed for bad_dag
Traceback (most recent call last):
  File "/Users/jhoran/Workspace/eda_astronomer/.venv/lib/python3.12/site-packages/airflow/models/dagrun.py", line 1451, in handle_dag_callback
    callback(context)
  File "/Users/jhoran/Workspace/eda_astronomer/.venv/lib/python3.12/site-packages/airflow/sdk/bases/notifier.py", line 136, in __call__
    self.render_template_fields(context)
  File "/Users/jhoran/Workspace/eda_astronomer/.venv/lib/python3.12/site-packages/airflow/sdk/bases/notifier.py", line 92, in render_template_fields
    jinja_env = self.get_template_env(dag=dag)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/jhoran/Workspace/eda_astronomer/.venv/lib/python3.12/site-packages/airflow/sdk/definitions/_internal/templater.py", line 79, in get_template_env
    return dag.get_template_env(force_sandboxed=False)
           ^^^^^^^^^^^^^^^^^^^^
AttributeError: 'SerializedDAG' object has no attribute 'get_template_env'

I tried running the same dag in astronomer, there I didn't see any failure but I also didn't get any log output, so I can only assume it's working there.

What you think should happen instead?

No response

Operating System

No response

Versions of Apache Airflow Providers

No response

Deployment

Virtualenv installation

Deployment details

No response

Anything else?

No response

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Activity

  1. jroachgolf84 commented on Apr 3, 2026

    @jroachgolf84
    Collaborator

    Just to confirm, this is running in Astronomer (you're able to see the logs), but not locally with the Astro CLI?

    @johnhoran, send a message in the #airflow-astronomer channel in Slack, and we can troubleshoot there.

  2. mscsy0104 commented on Apr 9, 2026

    @mscsy0104
    Contributor

    Hi there, I’m interested in working on this issue. I noticed that is already discussing it—is the task currently being handled? If not, I’d love to take it on and be assigned to this issue. Thanks!

  3. Quantum0uasar commented on May 21, 2026

    @Quantum0uasar

    I'd like to work on this fix!

    The issue is that when running airflow dags test, the DAG context doesn't set up the same task context as a real run, so notifiers that call task (from airflow.sdk) may fail with a serialization or context error.

    Looking at the commit a67e9a7 (Handle serialized DAGs in notifier templating), I'll investigate whether the fix is complete or if there are remaining edge cases. My plan:

    1. Reproduce the issue locally with the minimal example from the report
    2. Trace through the BaseNotifier rendering and airflow dags test code path
    3. Ensure serialized DAG context is properly handled during templating
    4. Add a test case to prevent regression

    Could a maintainer confirm whether this is still open after a67e9a7 or if there are specific edge cases remaining?

  4. added 7 commits that reference this issue on Jun 1, 2026
    6465711
    ca5a698
    7879076
    6631ba0
    e63742b
    4ab3680
    d8fdac9
  5. sameerpandey17 commented on Oct 13, 2026

    @sameerpandey17

    Still reproducible on main as of today. I also hit it with a notifier that defines template_fields, so it doesn't look limited to notifiers with none.

    I tested on main at 7f0d50cffc (Breeze, Python 3.11.16). After fetching, git diff HEAD upstream/main shows no differences in notifier.py or templater.py, so current main should behave the same.

    Setup is a Dag with a BaseNotifier subclass as on_failure_callback, run with airflow dags test <dag_id> 2026-01-01. The task fails as expected, then the callback crashes:

    File "task-sdk/src/airflow/sdk/bases/notifier.py", line 92, in render_template_fields
        jinja_env = self.get_template_env(dag=dag)
    File "task-sdk/src/airflow/sdk/definitions/_internal/templater.py", line 80, in get_template_env
        return dag.get_template_env(force_sandboxed=False)
    AttributeError: 'SerializedDAG' object has no attribute 'get_template_env'
    

    I got the same error with a bare-bones notifier and with this one that has a templated field:

    Dag with a templated notifier
    from __future__ import annotations
    
    from datetime import datetime
    
    from airflow.sdk import DAG, task
    from airflow.sdk.bases.notifier import BaseNotifier
    
    
    class TemplatedNotifier(BaseNotifier):
        template_fields = ("message",)
    
        def __init__(self, message: str):
            super().__init__()
            self.message = message
    
        def notify(self, context):
            self.log.info("Rendered message: %s", self.message)
    
    
    with DAG(
        dag_id="templated_notifier_test",
        start_date=datetime(2026, 1, 1),
        schedule=None,
        catchup=False,
        on_failure_callback=TemplatedNotifier(message="Dag {{ dag.dag_id }} failed"),
    ) as dag:
    
        @task
        def failing_task():
            raise Exception("designed to fail")
    
        failing_task()

    As an experiment I changed Templater.get_template_env to if dag and hasattr(dag, "get_template_env"): so it falls back to the default SandboxedEnvironment. With that, both Dags ran their callbacks without crashing, and the templated message rendered as Dag templated_notifier_test failed. I reverted it afterwards.

    One thing I didn't test is Dag-level custom filters or macros (user_defined_macros). I'd expect the fallback environment to be missing those, but that's just my reading of the code, not something I ran.

    I noticed #64993 and #67862 both take this approach (#67862 was closed because of the open-PR limit, not on its merits). I hope this reproduction helps. If #64993 has stalled and the maintainers are fine with it, I’d be glad to pick this up.

    (I also used AI in the process of understanding and testing)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions