Debugging Mwaa Workflow
AWSOfficialPublished by AWS
- Skill
- Review and audit
- Cloud and DevOps
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a systematic, read-only diagnostic framework for troubleshooting Amazon Managed Workflows for Apache Airflow (MWAA). It handles both Provisioned (Python DAG) and Serverless (YAML) environments by routing failures through a standardized 4-step process: detection, identification, categorization, and context analysis. It leverages AWS CLI commands to query MWAA APIs and CloudWatch logs, providing actionable root cause analysis, impact assessments, and remediation recommendations while maintaining production safety by never executing state-mutating commands autonomously.
What it does
- Detects and categorizes MWAA workflow failures including task crashes, import errors, and IAM denials.
- Queries MWAA Provisioned environments via invoke-rest-api and CloudWatch logs.
- Analyzes MWAA Serverless workflows using GetWorkflowRun and task instance logs.
- Provides a structured diagnostic report with root cause, impact, and remediation steps.
- Offers specific troubleshooting checklists for common issues like DAGs not appearing in the UI.
- Maintains security by performing only read-only operations and suggesting safe remediation commands.
When to use it
- When a DAG or task fails unexpectedly in an MWAA environment.
- When a DAG is not appearing in the Airflow UI.
- When diagnosing worker OOM (SIGKILL) or dependency drift issues.
- When investigating 'AccessDenied' or 'EntityNotFound' errors in workflow logs.
- When needing to distinguish between definition errors and task-execution failures.
Advantages
- Standardizes the diagnostic process across different MWAA deployment models.
- Prioritizes safe, read-only investigation to prevent accidental production changes.
- Provides clear, actionable remediation paths for complex issues like dependency drift.
- Reduces manual log-diving by automating the retrieval of relevant error details.
- Includes specific guidance for common, non-obvious issues like scheduler scan intervals.
Usage examples
- “Why did my workflow fail?”
- The agent will identify the environment flavor, list recent failed runs, pull the relevant error logs, and provide a structured report with the root cause and remediation steps.
- “My DAG is not showing up in the UI, help me debug.”
- The agent will walk through the DAG registration checklist, checking for import errors, scan intervals, dag_id collisions, and S3-sync delays.
- “Why is my worker crashing with a SIGKILL?”
- The agent will analyze the worker logs, confirm the environment class and memory constraints, and recommend moving heavy tasks to external services like Glue or EMR.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/aws/debugging-mwaa-workflow/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip debugging-mwaa-workflow.zip -d .agents/skills
Documentation by AWS
Debugging MWAA Workflows
AWS MCP server (optional but recommended): running the AWS CLI commands in this skill through the AWS MCP server gives sandboxed execution and audit logging. Every command here also works with the plain AWS CLI, so the skill does not require the MCP server or any MCP-only tools.
Diagnose and root-cause Amazon MWAA workflow failures, then report root cause, impact, and recommended remediation. Routes by flavor, then runs a shared 4-step diagnostic spine.
Guardrail — where this skill's own files live (MCP vs local install)
This skill can be loaded two ways, and they resolve the skill's own bundled files from different places. Determine how the skill was loaded before reading a reference:
Loaded through the AWS MCP
retrieve_skilltool: The skill is not installed on the local filesystem. You MUST fetch each reference viaretrieve_skillwith thefileparameter (e.g.file="references/failure-catalog.md") and read the returned content. Do NOTfile_readthese paths locally — they do not exist on disk.Installed locally (e.g.
.kiro/skills/debugging-mwaa-workflow/or~/.claude/skills/debugging-mwaa-workflow/): Read the files from the local skill directory using relative paths.
This distinction applies only to the skill's own packaged files. User data and
session artifacts are always read from and written to the user's working
directory. Never fetch or write customer data through retrieve_skill.
Step 0: Detect Flavor and Scope the Failure
Detect flavor
An environment name resolvable via
aws mwaa get-environmentmeans the environment is Provisioned.A
workflow/...ARN or anyaws mwaa-serverlesscontext means the environment is Serverless. A bare run identifier does NOT indicate flavor — Provisioned DAG runs also have run ids.If neither signal is present, ask: is the target MWAA Provisioned (Python DAG) or MWAA Serverless (YAML workflow)?
Route by complexity
Simple — a single named task or run failed with a clear exception. Jump to Step 2 for that task.
Standard — a run failed and the cause is unknown. Run the full Step 1 to Step 4 sweep.
Complex — intermittent or environment-wide (multiple DAGs, "worked yesterday", nothing appearing). Run the full sweep with emphasis on Step 3.
Step 1: Identify the Failure
Provisioned: list failed DAG runs and task instances via
aws mwaa invoke-rest-api (paths /dags/{id}/dagRuns and
/dags/{id}/dagRuns/{run_id}/taskInstances). If invoke-rest-api errors
(RestApiClientException), fall back to the Scheduler and DAGProcessing log
groups. Get version and config from aws mwaa get-environment. See
references/provisioned-diagnostics.md.
Serverless: aws mwaa-serverless list-workflow-runs, then
get-workflow-run. Read RunDetail.ErrorMessage — an empty TaskInstances
with a parser message is a definition error; Workflow execution failed with
populated TaskInstances is a task-execution failure. See
references/serverless-diagnostics.md.
Step 2: Get Error Details and Categorize
Pull the real exception past boilerplate:
Provisioned: read the Task log group first, then Worker/Scheduler/ DAGProcessing as the symptom directs.
Serverless: list-task-instances then get-task-instance to get each
task's LogStream, then read that stream in CloudWatch.
Then categorize in priority order — infra, then drift, then code-data —
using references/failure-catalog.md. The
category determines the Step 3 checks.
Step 3: Check Context (Why It Happened)
Run the context checks for the matched category from references/failure-catalog.md. Do not stop at the surface exception: a SIGKILL is an OOM story, a fresh import error on unchanged code is a drift story, a sensor timeout is an upstream-health story.
Step 4: Provide Actionable Output
Report in this exact structure:
Root Cause: <one-line diagnosis with the evidence that proves it>
Impact: <what failed, which runs, blast radius>
Immediate Fix: <the smallest change that unblocks>
Prevention: <the change that stops recurrence>
Commands: <exact read-only commands run, plus remediation commands for the user to run>Run only read-only operations. Present state-mutating remediation (clear/rerun/backfill for Provisioned; start-workflow-run or fix-and-redeploy for Serverless) as commands for the user to run, with the impact stated. Never execute them autonomously (production safety).
For the fix-and-redeploy path, use authoring-mwaa-workflow to regenerate a
compliant artifact.
Gotchas
Serverless has no Airflow web UI, no REST API, and no CLI token. Do not attempt
create-web-login-token,invoke-rest-api, or any Airflow REST path for Serverless.For Provisioned, always use
aws mwaa invoke-rest-api(notcreate-web-login-token+ curl).invoke-rest-apireaches VPC-only web servers without network access.GetWorkflowRun.RunDetail.ErrorMessagedistinguishes a definition error (emptyTaskInstances) from a task-execution failure (Workflow execution failed, populatedTaskInstances). Read it before pulling task logs.The Serverless log group defaults to
/aws/mwaa-serverless/{workflow-id}/but can be a custom group; confirm viaget-workflowLoggingConfigurationbefore assuming the path.A DAG not appearing has several causes — an import/parse error, the scheduler scan interval (
scheduler.dag_dir_list_interval, ordag_processor.refresh_intervalon Airflow 3.x) not yet elapsed, adag_idcollision, or S3-sync delay — and is rarely a broken DAG. CheckGET /importErrorsandGET /dags/{dag_id}via invoke-rest-api (and the DAGProcessing logs); see the failure catalog's "DAG not appearing in the UI" checklist before concluding the code is wrong.A worker SIGKILL is an OOM signal. Recommend moving work to Glue/EMR/Lambda; scaling workers alone does not fix per-task memory pressure.
MWAA re-resolves dependencies on environment update, so an unchanged DAG can start failing on import with no code change. Treat no-code-change import failures as drift.
Serverless
PythonOperator/BashOperatortasks run custom code from a--codepackage. A run that fails to extract the package or hitsModuleNotFoundErroris a packaging problem (wrong-platform wheel, missing dep, bad layout), not a YAML definition error. See the failure catalog's serverless custom-code section.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
RestApiClientException (Provisioned) | Mis-scoped execution role or service error | Fall back to Scheduler/DAGProcessing log groups |
ResourceNotFoundException on get-workflow-run | Wrong workflow ARN or run id | Re-list with list-workflow-runs |
| Task log stream empty (Serverless) | Wrong log group assumed | Read LoggingConfiguration from get-workflow |
| No task logs but run FAILED | Definition/parse error | Read RunDetail.ErrorMessage; fix the YAML |
References
references/provisioned-diagnostics.md — Provisioned data sources and read-only commands
references/serverless-diagnostics.md — Serverless API, log group, failure classes
references/failure-catalog.md — category-keyed context checks and remediation
Security Considerations
Read-only by default: diagnosis uses only read/list/describe calls. Remediation (clear/rerun/backfill, IAM or key-policy changes) is presented as commands for the user to run, never executed autonomously.
Least-privilege IAM: when an
AccessDeniedis a genuine permission gap, recommend the minimalAction/Resourcefrom the error — never a wildcard; distinguish it from a nonexistent-resource typo (do not broaden IAM then).Cross-account: KMS key-policy / assume-role changes are human-gated and coordinated with the resource owner.
No secret exposure: do not surface credentials or connection strings from logs or API responses in the diagnosis output.
Files
- ATTRIBUTION.mdAdded by AutoGineer926 B
- LICENSELicence file added by AutoGineer9.9 KiB
- NOTICELicence file added by AutoGineer67 B
- SKILL.md9.1 KiB
- references/failure-catalog.md11.4 KiB
- references/provisioned-diagnostics.md6.0 KiB
- references/serverless-diagnostics.md2.9 KiB
references/failure-catalog.md
MWAA Failure Catalog
Category-keyed context checks and remediation. Categorize in this priority order: infra, then drift, then code-data. Apply the first that matches the evidence.
Category: infra (check first)
| Symptom | Root cause | Context check | Remediation to recommend |
|---|---|---|---|
Task exits with Negsignal.SIGKILL / SIGTERM | Worker OOM | Worker log group; MaxWorkers and environment class from get-environment | Move heavy work to Glue/EMR/Lambda; stagger schedules; increase environment class. Scaling workers alone does not fix per-task OOM. |
| Tasks queued, never run | Autoscaling ceiling or scheduler load | Worker/Scheduler logs; MaxWorkers | Raise MaxWorkers; reduce core.parallelism; stagger start times |
AccessDenied / EntityNotFound in task logs | IAM gap OR wrong/nonexistent resource OR cross-account | Read the exception's resource ARN, then check which failure it is (below) | Depends on which of the three — see the disambiguation note |
| DAG not appearing in UI | Import/parse error, scan interval not elapsed, dag_id collision, not-yet-active, or S3-sync delay | GET /importErrors and GET /dags/{dag_id} via invoke-rest-api; DAGProcessing log group; confirm DagS3Path object exists | See the DAG not appearing in the UI checklist below — the cause determines the fix |
DAG not appearing in the UI
Not a single cause. When you explain the causes — or how to check a DAG that
is not appearing — cover all five below, each paired with its specific
check, rather than stopping at the first likely one. The Airflow REST API via
invoke-rest-api is the fastest check for most (see provisioned-diagnostics.md):
a thorough answer names both scan-interval config keys in step 2 and the
GET /importErrors and GET /dags/{dag_id} checks (the latter reading
last_parsed_time, fileloc, and is_active/is_stale). Do not conclude the
code is broken until 1 and 2 are ruled out.
Import / parse error — the file is present but fails to parse, so it never registers. Check
GET /importErrors(Airflow REST API) for the file's traceback, or the DAGProcessing CloudWatch log group. Fix the code; it reappears on the next parse.Scheduler scan interval not yet elapsed — a valid new file only lists after the DAG-directory scan runs. That cadence is
scheduler.dag_dir_list_interval(Airflow 2.x) /dag_processor.refresh_interval(Airflow 3.x). The S3-to-container sync is only ~30s; the listing delay is this scan interval. Wait one interval before assuming a defect.dag_idcollision — if another file already defines the samedag_id, Airflow keeps one and silently drops the duplicate, so the new file "does not appear." Confirm thedag_idis unique across the wholedags/prefix.Parsed but not yet registered/active — after the first successful parse the DAG registers.
GET /dags/{dag_id}and readlast_parsed_timeandfileloc(present on both Airflow 2.x and 3.x) to confirm it parsed and points at the file you uploaded. Checkis_activeon Airflow 2.x; on Airflow 3.x that field was replaced byis_stale(inverted — a stale DAG's file no longer parses). Thehas_import_errorsflag on the same object points straight at a parse failure.S3-sync delay — the object must land under the environment's
DagS3Path. Confirm the object exists at that key; MWAA syncs it to the containers within ~30s.
Disambiguating AccessDenied / EntityNotFound
A denial on a resource is one of four failures; the fix differs for each. Read
the resource ARN from the exception. Determine the account and region the
resource is expected in — this is NOT always the environment's own account.
Cross-account access is common: the execution role may access resources in
another account via resource policies (S3, SNS, KMS, etc.) or via
sts:AssumeRole into a role in the target account (configured as an Airflow
AWS connection with IAM role type in Provisioned). Check existence from the
account/role that should have access:
Resource exists, role lacks the action (true IAM gap) — the classic case. Add the missing action to the execution role (same-account) or to the assumed role (cross-account). Do not broaden to wildcard. HUMAN-GATED.
Resource does not exist — the identifier is a placeholder, a typo, or in a different region.
AccessDenied(notNoSuchBucket) is common here because IAM denies before existence is revealed. Fix the identifier in the DAG/workflow (ARTIFACT fix via authoring-mwaa-workflow), not the role.Resource is cross-account, resource-policy path — the ARN's account differs from the execution role's and access is via a resource policy on the target (S3 bucket policy, SNS topic policy, KMS key policy). Needs both: the resource policy granting the execution role's principal, and the execution role having the action. A role change alone or a resource policy alone will not resolve it. HUMAN-GATED.
Resource is cross-account, assume-role path — the task assumes a role in the target account (Provisioned: Airflow AWS connection with IAM role type; Serverless: not applicable — no connections). The denial is on the assumed role, not the execution role. Check: (a) execution role has
sts:AssumeRoleon the target role ARN, (b) the target role's trust policy allows the execution role as principal, (c) the target role has the needed action on the resource. HUMAN-GATED.
Do not reflexively broaden IAM: adding permissions for a resource that does not exist (case 2) hides the real bug and leaves a standing over-grant.
Extracting the required IAM policy from an AccessDeniedException
AWS error messages for access denials follow a consistent format that contains everything needed to construct the missing IAM statement:
User: arn:aws:sts::<account>:assumed-role/<role>/...
is not authorized to perform: <action>
on resource: <resource-arn>
because no identity-based policy allows the <action> actionExtract these three fields and construct the minimum policy:
{
"Effect": "Allow",
"Action": ["<action>"],
"Resource": "<resource-arn>"
}For the resource ARN, determine the appropriate scope:
If the ARN ends in a specific resource ID, keep it exact for least privilege.
If the ARN contains a log group or prefix pattern (e.g.,
/aws/sagemaker/TrainingJobs:*), use the pattern with a wildcard suffix to cover log streams or child resources.If the service requires multiple related actions together (e.g.,
DescribeLogStreamsoften needsGetLogEvents), check AWS documentation for the minimum action set.
After identifying the needed statement, verify which role requires it:
The MWAA execution role (for actions the DAG tasks perform directly).
A service role (e.g., Glue role, SageMaker role) if the denied principal is not the MWAA role.
A cross-account assumed role (case 4 above).
Present the exact policy statement and target role to the user as a HUMAN-GATED remediation.
Category: drift (check when code did not change)
A DAG that passed last week and now fails on import, with no code change, is almost always dependency drift. MWAA re-resolves dependencies on environment update.
Three artifact paths can carry versioned objects (get-environment returns both
the S3 path and the *S3ObjectVersion in use when bucket versioning is
enabled). Always compare the specific object version the environment is
using, not the latest object at that path — a newer upload not yet picked up
by the environment is irrelevant to the current failure.
requirements.txt (
RequirementsS3Path/RequirementsS3ObjectVersion): compare the pinned version in use against the last known good. Unpinned packages resolve to new releases on environment update.plugins.zip (
PluginsS3Path/PluginsS3ObjectVersion): may bundle.whlfiles providing Python packages outside of requirements.txt. A changed plugins.zip can introduce or remove packages, native shared libraries, or operator plugins. Diff contents (unzip -l) between the current version and the prior one.Startup script (
StartupScriptS3Path/StartupScriptS3ObjectVersion): installs system libraries (yum/apt) that Python packages depend on (e.g.,libpq-develforpsycopg2,unixODBC-develforpyodbc). A changed or removed startup script can break packages that compiled against those libraries at install time.Check whether the environment version was bumped (get-environment
AirflowVersion) — a version change re-resolves the entire provider stack.
Remediation to recommend: pin exact versions in requirements.txt and use the
MWAA constraints file for the target Airflow version; pin .whl contents in
plugins.zip; pin system library versions in the startup script; use S3 object
versioning and reference explicit *S3ObjectVersion values in environment
config to prevent unintended drift on upload.
Category: code-data (check last)
Recent DAG changes: diff the DAG file in S3 against the prior version.
Data volume spike: an operator that worked on small input may time out or OOM on large input — inspect input size for the failing run's data interval.
Upstream health: a sensor timeout usually means the upstream producer is late, not that the DAG is broken.
Remediation to recommend: fix the code or data; adjust timeouts/retries per the authoring-mwaa-workflow rules.
Category: serverless custom-code failures (Python/Bash)
MWAA Serverless PythonOperator/BashOperator tasks add failure modes the
Provisioned rows above do not cover. Serverless only.
| Symptom | Root cause | Context check | Remediation to recommend |
|---|---|---|---|
ModuleNotFoundError / ImportError in task log | Dep not bundled AND not pre-installed, OR wheel built for the wrong platform | Compare the import against the pre-installed list; inspect the code package layout | Repackage the dep as a wheel matching the current MWAA Serverless platform and Python version (fetch from the operators-python-bash-detail doc) at the zip root; do not bundle pre-installed packages |
| Run fails, "cannot extract code package" / corrupt environment | Bad zip: files not at root, __pycache__ included, or > 250 MB | Inspect the uploaded object size and layout | Repackage with all files at the root, excluding __pycache__; keep uncompressed size <= 250 MB |
| Task uses an unexpected package version | Bundled version shadowed by a pre-installed package | Check whether the package is on the pre-installed list | Design against the pre-installed version, or vendor under a different name if a different version is essential |
| Network call times out / connection refused | No internet access by default | Confirm the workflow has no NetworkConfiguration | Recommend a NetworkConfiguration VPC with egress, or move the network step to Lambda/Glue. HUMAN-GATED (VPC/networking) |
| Python task killed / OOM | Worker fixed at 1 vCPU / 3 GiB (cannot scale like Provisioned; confirm current specs from the MWAA Serverless docs at runtime) | Task log for MemoryError/SIGKILL; data volume for the run | Offload heavy work to Glue/EMR/Lambda; reduce in-memory footprint. Worker scaling is not available on Serverless |
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- AWS
- Publisher
- AWS (Official)
- Source
- aws/agent-toolkit-for-aws · plugins/aws-data-analytics/skills/debugging-mwaa-workflow · commit 0a218f8
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- NOTICE (added by AutoGineer from NOTICE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
- Also distributed in
- aws/agent-toolkit-for-aws
AutoGineer is not affiliated with or endorsed by AWS.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download debugging-mwaa-workflow.zip