<@ULVA73B9P> An error was encountered while runni...
# ask-marvin
m
@Marvin An error was encountered while running hook 'pipeline_alert' Traceback (most recent call last): File "/home/mip/ds_pipelines/venv/lib/python3.10/site-packages/prefect/runner/runner.py", line 1573, in _run_hooks await from_async.call_in_new_thread( File "/home/mip/ds_pipelines/venv/lib/python3.10/site-packages/prefect/_internal/concurrency/calls.py", line 374, in aresult return await asyncio.wrap_future(self.future) File "/home/mip/ds_pipelines/venv/lib/python3.10/site-packages/prefect/_internal/concurrency/calls.py", line 399, in _run_sync result = self.fn(*self.args, **self.kwargs) File "/home/mip/ds_pipelines/src/utils/utils.py", line 39, in pipeline_alert state_emoji_dict = {'Failed':'⚠️' , 'Crashed': '⚠️' , 'Running':"🚀" , "Completed": "",'Cancelled':"🚫","Cancelling":""} KeyError: 'Cancelling' def pipeline_alert(flow: Flow, flow_run: FlowRun, state: State): flow_state = state.name print(flow_state) state_emoji_dict = {'Failed':'⚠️' , 'Crashed': '⚠️' , 'Running':"🚀" , "Completed": "",'Cancelled':"🚫","Cancelling":""} state_emoji = state_emoji_dict.get(flow_state, '') subject = f'{state_emoji} {SOURCE.upper()} - {flow_run.name} - {flow_state} - {APP_ENV.upper()}' text = f""" See {PREFECT_UI_URL.value()}/flow-runs/flow-run/{flow_run.id} the flow run in the UI\n\n """ body_html = f""" <html> <body> <p>{text}:</p> </body> </html> """ sender = 'reports@credilinq.ai' print(subject) print(text) ses = ses_client() response = ses.send_email( Source=sender, Destination={ 'ToAddresses': ['DataScienceTeam@credilinq.ai'] }, Message={ 'Subject': { 'Data': subject }, 'Body': { 'Html': { 'Data': body_html } } } ) print(response) @flow(name="AMAZON",flow_run_name='{seller_id}-{data_cycle}', log_prints=True,task_runner=ThreadPoolTaskRunner(max_workers=2) , on_failure=[pipeline_alert], on_crashed= [pipeline_alert], on_running=[pipeline_alert],on_completion=[pipeline_alert], on_cancellation=[pipeline_alert]) solve this
m
thought for 183.9 seconds
You’re hitting a KeyError for 'Cancelling' inside the hook. In Prefect 3.x the state name is indeed spelled with a double “L” — 'Cancelling'. If anywhere you index a dict with
state.name
and your mapping does not contain that exact key (or you’re using
[...]
instead of
.get()
), you’ll get this KeyError. Two solid fixes: 1) Keep mapping by state name but ensure the exact spellings are present and always use
.get(...)
with a default. 2) Prefer mapping by state type instead of name. It’s more robust because multiple names map to the same type (e.g., 'Running' and 'Retrying' are both RUNNING). Here’s a drop-in update that avoids KeyErrors and covers the common types:
Copy code
from prefect import flow
from prefect.states import State
from prefect.client.schemas.objects import Flow, FlowRun  # adjust imports if needed

def pipeline_alert(flow: Flow, flow_run: FlowRun, state: State):
    # Prefer state.type.value for stable matching
    state_type = state.type.value  # e.g., 'RUNNING', 'CANCELLING', 'COMPLETED', etc.

    emoji_by_type = {
        'FAILED': ':warning:',
        'CRASHED': ':warning:',
        'RUNNING': ':rocket:',
        'COMPLETED': ':white_check_mark:',
        'CANCELLED': ':no_entry_sign:',
        'CANCELLING': ':x:',
        # Optional: cover more types
        'SCHEDULED': ':calendar:',
        'PENDING': ':hourglass_flowing_sand:',
        'PAUSED': ':pause_button:',
    }
    state_emoji = emoji_by_type.get(state_type, ':question:')

    subject = f"{state_emoji} {SOURCE.upper()} - {flow_run.name} - {state.name} - {APP_ENV.upper()}"

    # Use real HTML so the link is clickable in email
    body_html = f"""
<html>
  <body>
    <p>See <a href="{PREFECT_UI_URL.value()}/flow-runs/flow-run/{flow_run.id}">the flow run in the UI</a></p>
  </body>
</html>
""".strip()

    # For SES, use plain email addresses (no Slack mailto markup)
    sender = "<mailto:reports@credilinq.ai|reports@credilinq.ai>"
    to_addresses = ["<mailto:DataScienceTeam@credilinq.ai|DataScienceTeam@credilinq.ai>"]

    ses = ses_client()
    response = ses.send_email(
        Source=sender,
        Destination={'ToAddresses': to_addresses},
        Message={
            'Subject': {'Data': subject},
            'Body': {'Html': {'Data': body_html}}
        }
    )
    print(response)
Why this works: - Uses
state.type.value
so you don’t need to remember the exact casing/spelling of names like 'Cancelling'. - Provides a default emoji for unknown states, preventing KeyErrors. - Fixes SES address formatting to plain emails (SES will reject
<mailto:...>
markup). For reference on exact state names and types in Prefect 3.x, see: - Concepts: States - API Reference: prefect.states If you’d rather keep name-based mapping, ensure you include 'Cancelling' (double L) and use
.get(flow_state, ':question:')
everywhere you access the mapping.