The MWAA Plugin Puzzle That Cost Me Hours (And How You Can Avoid It)
A tale of zip files, directory structures, and the tiny details that break production deployments
The MWAA Plugin Puzzle That Cost Me Hours (And How You Can Avoid It)
A tale of zip files, directory structures, and the tiny details that break production deployments
Ever spent hours debugging something, only to discover the fix was embarrassingly simple? Welcome to my Tuesday.
I was setting up custom sensors for Amazon Managed Workflows for Apache Airflow (MWAA), and everything looked perfect. The code was tested. The DAGs were ready. The plugin zip file was uploaded to S3. But Airflow kept throwing import errors like it had never heard of my beautiful custom sensor.
Spoiler alert: It was the zip file structure. Of course it was.
The Setup
I had built a custom S3 date range sensor — nothing fancy, just a sensor that checks for data across a date range in S3. The kind of thing you’ve probably written a dozen times.
The code worked locally. It worked in my dev environment. It passed all tests. So I zipped it up and deployed it to MWAA.
And then… nothing. Import errors. Module not found. The classic.
The Investigation
After checking the obvious things (S3 paths, IAM permissions, MWAA environment updates), I finally did what I should have done first — I actually looked at what was inside my zip file.
I had two versions sitting in my downloads folder:
- One from my first attempt
- One from my “fixed” attempt
Same code inside. Same file sizes for the actual Python files. But one worked, and one didn’t.
The difference?
Version 1 (broken):
my_project/plugins/
├── __init__.py
└── sensors/
├── __init__.py
└── s3_date_range_sensor.py
Version 2 (working):
sensors/
├── __init__.py
└── s3_date_range_sensor.py
__init__.py
That’s it. That’s the whole difference. The nested directory path.
Why This Matters
MWAA expects your plugin structure to start immediately at the zip root. When Airflow unpacks your plugins.zip, it looks for Python modules right there at the top level.
So when you write this in your DAG:
from sensors.s3_date_range_sensor import S3DateRangeSensor
Airflow is looking for a sensor
folder at the root of the extracted plugins. If your zip file has
my_project/plugins/sensors/...
, Airflow can’t find it. It’s not going to traverse your nested directory structure hoping to stumble upon your code.
The Fix
When creating your plugins.zip, make sure you’re zipping from the right directory.
Wrong approach:
cd ~/projects
zip -r plugins.zip my_project/plugins/
Right approach:
cd ~/projects/my_project/plugins
zip -r plugins.zip .
Or if you want to be more explicit:
cd ~/projects/my_project/plugins
zip -r ../../../plugins.zip sensors/ __init__.py
A Quick Sanity Check
Before uploading, always verify your zip structure:
unzip -l plugins.zip
You should see something like:
Archive: plugins.zip
Length Date Time Name
--------- ---------- ----- ----
0 01-07-2025 18:07 sensors/
156 01-07-2025 18:07 sensors/__init__.py
23525 01-07-2025 18:07 sensors/s3_date_range_sensor.py
89 01-07-2025 18:07 __init__.py
Not this:
Archive: plugins.zip
Length Date Time Name
--------- ---------- ----- ----
0 01-08-2025 11:46 my_project/plugins/sensors/
...
Lessons Learned
- Always inspect your zip files before deploying. A quick
unzip -ltakes two seconds and saves hours of debugging.
2. Zip from the right directory. The directory you run from matters enormously.
3. MWAA is particular. It does what the documentation says, even when you think you know better.
4. Keep your failed attempts around. Having both zip files let me actually compare and find the issue. If I’d deleted the broken one, I’d probably still be debugging.
The Broader Point
This wasn’t a code problem. The Python was identical in both zip files — byte for byte the same. This was purely a packaging problem.
In the world of managed services like MWAA, understanding how to package your code is just as important as the code itself. The service has expectations about structure, and it’s not going to figure out what you meant. You have to meet it where it is.
Have you ever spent way too long on a packaging issue? I’d love to hear about it in the comments — misery loves company.
Tags: #AWS #MWAA #Airflow #Python #DevOps #DataEngineering
메타데이터
- post_id
- 2bef2295438b
- slug
- the-mwaa-plugin-puzzle-that-cost-me-hours-and-how-you-can-avoid-it-2bef2295438b
- url
- https://medium.com/@sanjeebmeister/the-mwaa-plugin-puzzle-that-cost-me-hours-and-how-you-can-avoid-it-2bef2295438b
- canonical_url
- https://medium.com/@sanjeebmeister/the-mwaa-plugin-puzzle-that-cost-me-hours-and-how-you-can-avoid-it-2bef2295438b
- author_url
- https://medium.com/@sanjeebmeister
- status
- ok
- fetched_at
- 2026-07-07 08:01:35