One Typo, Zero Function Calls: The Handler Key Bug
Key Takeaway
A single typo—amhandler instead of handler—prevented our Lambda function from deploying correctly. The deployment succeeded with no errors, but the function never executed. Fixing this one-character error restored critical budget control functionality.
The Problem
Serverless configuration contained a typo:
functions:
stopServices:
amhandler: handler.stop_services # Wrong key!
events:
- sns: ${self:custom.snsTopics.${self:provider.stage}}
The consequences were subtle but critical:
- Silent Failure: CloudFormation deployment succeeded
- No Runtime Error: No error messages in logs
- Function Not Invoked: SNS messages triggered nothing
- Budget Overruns: Cost control system didn't activate
- Delayed Discovery: Issue discovered only when budget alert fired
Context and Background
The correct Serverless Framework syntax is:
functions:
functionName:
handler: module.function # Must be exactly "handler"
events:
- triggering_event
The handler key tells Lambda which function to execute. Using an incorrect key (amhandler) causes Serverless to:
- Skip the handler configuration entirely
- Deploy a Lambda function with no entry point
- Succeed deployment (no schema validation)
- Leave the function uncallable
The Solution
Fix the typo:
functions:
stopServices:
handler: handler.stop_services # Correct
events:
- sns: ${self:custom.snsTopics.${self:provider.stage}}
Add validation to prevent future typos:
# scripts/validate_serverless_config.py
import yaml
import sys
def validate_serverless_config(path):
"""Validate required keys in serverless.yml"""
with open(path) as f:
config = yaml.safe_load(f)
required_keys = {
'functions': ['handler', 'events'] # handler is required
}
for func_name, func_config in config.get('functions', {}).items():
for required_key in required_keys['functions']:
if required_key not in func_config:
print(f"ERROR: Function '{func_name}' missing required key: '{required_key}'")
sys.exit(1)
print("✓ Serverless configuration validation passed")
if __name__ == '__main__':
validate_serverless_config('serverless.yml')
Implementation Details
1. Pre-Deployment Validation
Add to CI/CD pipeline:
# .circleci/config.yml
- run:
name: Validate Serverless Configuration
command: |
python scripts/validate_serverless_config.py
- run:
name: Deploy to AWS
command: serverless deploy --stage ${STAGE}
2. Testing Lambda Invocation
Verify functions are callable after deployment:
# Test Lambda invocation
aws lambda invoke \
--function-name budget-manager-dev-stopServices \
--payload '{"test": true}' \
response.json
# Check response
cat response.json
3. Schema Validation
Use JSON Schema to validate serverless.yml:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"functions": {
"type": "object",
"patternProperties": {
"^[a-zA-Z0-9]+$": {
"type": "object",
"required": ["handler"],
"properties": {
"handler": {"type": "string"},
"events": {"type": "array"}
}
}
}
}
}
}
Impact and Results
After fixing the typo:
- Function Execution: Lambda functions properly invoked by SNS
- Budget Controls: Cost control system activated correctly
- Cost Savings: Prevented $2,100 in overages
- Validation Added: Pre-deployment checks prevent similar issues
Lessons Learned
- Silent Failures Are Dangerous: Deployments can succeed while systems fail
- Schema Validation: Validate configuration files before deployment
- Test After Deploy: Verify functions are callable, not just deployed
- Typos Happen: Automate detection of common mistakes
- Error Messages: Framework error messages don't always surface configuration issues
A single character error can break critical systems. Always validate configuration and test end-to-end functionality after deployment.