Skill 65 · Debugging Mwaa Workflow
Subchapter 65.1
references/failure-catalog.mdMarkdown11 KBView on GitHub
Category-keyed context checks and remediation. Categorize in this priority order: infra, then drift, then code-data. Apply the first that matches the evidence.
| 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 |
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.
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.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_id collision — if another file already defines the same dag_id,
Airflow keeps one and silently drops the duplicate, so the new file “does not
appear.” Confirm the dag_id is unique across the whole dags/ prefix.GET /dags/{dag_id} and read last_parsed_time and
fileloc (present on both Airflow 2.x and 3.x) to confirm it parsed and
points at the file you uploaded. Check is_active on Airflow 2.x; on Airflow
3.x that field was replaced by is_stale (inverted — a stale DAG’s file no
longer parses). The has_import_errors flag on the same object points
straight at a parse failure.DagS3Path.
Confirm the object exists at that key; MWAA syncs it to the containers within
~30s.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:
AccessDenied (not NoSuchBucket) 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.sts:AssumeRole on 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.
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:
/aws/sagemaker/TrainingJobs:*), use the pattern with a wildcard suffix to
cover log streams or child resources.DescribeLogStreams often needs GetLogEvents), check AWS documentation for
the minimum action set.After identifying the needed statement, verify which role requires it:
Present the exact policy statement and target role to the user as a HUMAN-GATED remediation.
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.
RequirementsS3Path / RequirementsS3ObjectVersion):
compare the pinned version in use against the last known good. Unpinned
packages resolve to new releases on environment update.PluginsS3Path / PluginsS3ObjectVersion): may bundle
.whl files 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.StartupScriptS3Path / StartupScriptS3ObjectVersion):
installs system libraries (yum/apt) that Python packages depend on (e.g.,
libpq-devel for psycopg2, unixODBC-devel for pyodbc). A changed or
removed startup script can break packages that compiled against those
libraries at install time.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.
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 (opens in a new tab)) 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 |