Plugin: lambda-securityRules
require-timeout-handling
ESLint rule documentation for require-timeout-handling
📡 Live from GitHub — This documentation is fetched directly from require-timeout-handling.md and cached for 6 hours.
Keywords: Lambda, timeout, context, getRemainingTimeInMillis, AbortController, CWE-400, AWS, serverless CWE: CWE-400
Require timeout handling in Lambda handlers with external calls
Warns when Lambda handlers make external calls without checking remaining execution time. This rule is part of eslint-plugin-lambda-security and provides LLM-optimized error messages.
⚠️ Reliability rule | 💡 Provides suggestions | 📋 Set to warn in recommended
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-400 (Resource Issues) |
| Severity | Medium (reliability concern) |
| Auto-Fix | 💡 Suggests timeout check patterns |
| Category | Reliability |
| Best For | Lambda functions making HTTP, DB, or SDK calls |
Why This Matters
| Risk | Impact | Solution |
|---|---|---|
| ⏱️ Cold Timeout | Function times out mid-operation | Check remaining time before calls |
| 🔄 No Cleanup | Resources not released on timeout | Use AbortController for cancellation |
| 💸 Costs | Timeout = full duration billing | Fail fast when time is low |
Rule Details
This rule detects Lambda handlers that:
- Have a
contextparameter (Lambda context object) - Make external calls (fetch, axios, SDK operations, database queries)
- Do NOT use
context.getRemainingTimeInMillis()orAbortController
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
allowInTests | boolean | true | Allow in test files |
{
rules: {
'lambda-security/require-timeout-handling': ['warn', {
allowInTests: true
}]
}
}Examples
❌ Incorrect
// No timeout check - function may timeout mid-request
export const handler = async (event, context) => {
const data = await fetch('https://api.example.com/data'); // ❌ No timeout handling
const result = await dynamoDB.send(new GetCommand(params)); // ❌ May not complete
return { statusCode: 200, body: JSON.stringify(result) };
};✅ Correct
// Check remaining time before external calls
export const handler = async (event, context) => {
const remainingTime = context.getRemainingTimeInMillis(); // ✅ Check time
if (remainingTime < 5000) {
return {
statusCode: 503,
body: JSON.stringify({ error: 'Insufficient time remaining' }),
};
}
const controller = new AbortController(); // ✅ Cancellation support
const timeout = setTimeout(() => controller.abort(), remainingTime - 1000);
try {
const response = await fetch('https://api.example.com/data', {
signal: controller.signal,
});
return { statusCode: 200, body: JSON.stringify(await response.json()) };
} finally {
clearTimeout(timeout);
}
};✅ Also Correct: Promise.race Pattern
export const handler = async (event, context) => {
const fetchPromise = fetch('https://api.example.com/data');
// Race between fetch and timeout
const result = await Promise.race([
// ✅ Timeout pattern detected
fetchPromise,
new Promise((_, reject) =>
setTimeout(
() => reject(new Error('Timeout')),
context.getRemainingTimeInMillis() - 1000,
),
),
]);
return { statusCode: 200, body: JSON.stringify(result) };
};Timeout Handling Patterns
Pattern 1: Time Check + Early Exit
const MINIMUM_TIME_MS = 5000;
export const handler = async (event, context) => {
if (context.getRemainingTimeInMillis() < MINIMUM_TIME_MS) {
console.warn('Insufficient time for operation');
return { statusCode: 503, body: 'Service Unavailable' };
}
// Proceed with operation
};Pattern 2: AbortController with Timeout
export const handler = async (event, context) => {
const controller = new AbortController();
const safeTimeout = context.getRemainingTimeInMillis() - 2000;
const timeoutId = setTimeout(() => {
console.log('Aborting request due to Lambda timeout');
controller.abort();
}, safeTimeout);
try {
return await performOperation({ signal: controller.signal });
} finally {
clearTimeout(timeoutId);
}
};Pattern 3: AWS SDK with AbortController (v3)
import { DynamoDBClient, GetItemCommand } from '@aws-sdk/client-dynamodb';
export const handler = async (event, context) => {
const controller = new AbortController();
const client = new DynamoDBClient({});
setTimeout(
() => controller.abort(),
context.getRemainingTimeInMillis() - 1000,
);
const result = await client.send(new GetItemCommand(params), {
abortSignal: controller.signal, // ✅ SDK v3 supports AbortSignal
});
return result.Item;
};Related Rules
no-unbounded-batch-processing- Limit batch sizesno-error-swallowing- Don't swallow timeout errors
Known False Negatives
Custom Context Variable Names
Why: Non-standard context names not tracked.
// ❌ NOT DETECTED - unusual parameter name
export const handler = async (event, lambdaCtx) => {
await fetch(url); // No warning if 'lambdaCtx' not recognized
};Mitigation: Use standard parameter names (context, ctx).
Further Reading
- Lambda Context Object - AWS documentation
- CWE-400: Uncontrolled Resource Consumption - Official CWE entry
- AbortController in Node.js - Node.js docs