Why You Should Care
Ever run python -m your.module and get... nothing? No errors, exit code 0, but your code never actually runs? I just spent an hour debugging this exact problem.
Here's what I learned.
The Problem
I was running a CLI command via Jenkins:
$ python -m monitoring_sdk.core.cli metabase-check --config config.yaml
$ echo $?
0
$ ls reports/
# Empty - nothing was created
Exit code 0 means success, right? But nothing happened. No output, no files, no errors. Just... silence.
The Root Cause
Missing __main__ entrypoint.
When you run python -m module.path, Python imports the module but doesn't automatically call your main() function. You need to explicitly tell it what to run.
The Quick Fix
Add one of these (or both):
Option 1: Create __main__.py (Recommended)
# monitoring_sdk/core/__main__.py
from monitoring_sdk.core.cli import main
if __name__ == "__main__":
main()
Option 2: Add to your main file
# monitoring_sdk/core/cli.py
# ... your code ...
if __name__ == "__main__":
main()
That's it. Problem solved.
What Actually Happens
When you run python -m monitoring_sdk.core.cli, Python:
- Imports
monitoring_sdk/core/cli.py - Executes module-level code (imports, decorators, function definitions)
-
Stops - it doesn't call
main() - Exits with code 0
So you get:
- ✅ Module imported
- ✅ Functions defined
- ❌ Nothing executed
- ✅ Exit code 0 (looks like success!)
This is what I call a "silent failure" - the worst kind.
How I Debugged It
Step 1: Added logging everywhere
import logging
logger = logging.getLogger(__name__)
def metabase_check(config, output):
logger.info("Starting command") # This never appeared
# ... code ...
Step 2: Checked what WAS running
$ DEBUG=true python -m monitoring_sdk.core.cli metabase-check
DEBUG - Package initialized # Module imported
DEBUG - Monitors initialized # Module imported
# ... nothing else
Package initialization logs appeared (because __init__.py runs on import), but my function logs didn't. That's when I realized: the function was never called.
Step 3: Tried --help
$ python -m monitoring_sdk.core.cli --help
# No output at all
If even --help doesn't work, the entrypoint is definitely missing.
How Python Looks for Entrypoints
When you run python -m module.path:
- Look for
module/path/__main__.py→ Run it - Otherwise, run
module/path.py(but needif __name__ == "__main__")
| How You Run It | What You Need |
|---|---|
python -m module.path |
__main__.py |
python script.py |
if __name__ == "__main__" |
Why This Bit Me (AI-Generated Code)
Full transparency: I was using AI to generate code quickly. The AI created the CLI structure perfectly - decorators, commands, options - but forgot the entrypoint.
I assumed "AI generated it, so it's complete." I didn't even check. That was my mistake.
Lesson learned: AI is great for boilerplate, but you still need to verify the basics.
The Fix in Action
After adding __main__.py:
$ python -m monitoring_sdk.core.cli metabase-check --config config.yaml
INFO - Starting card check
INFO - Card check completed: status=OK
INFO - Report generated: file=reports/summary.md
INFO - Command completed: status=OK
$ ls reports/
summary.md # Finally!
Key Takeaways
-
python -mrequires an explicit entrypoint - Exit code 0 doesn't mean your code ran
- Silent failures are hard to debug - add logging early
- Even with AI-generated code, verify the basics
The worst bugs are the simple ones you don't think to check.
If you're interested in more troubleshooting processes and decision-making in engineering, I write about them here: https://tielec.blog/
Top comments (0)