Introduction

AWS Lambda provisioned concurrency allocates pre-initialized execution environments that are ready to respond immediately to invocations. Unlike on-demand Lambda functions that must initialize the runtime and execute handler code before processing requests, provisioned concurrency maintains warm environments that eliminate initialization latency. This feature is essential for latency-sensitive applications like API backends, real-time data processing, and interactive user experiences.

However, provisioned concurrency only eliminates cold starts for traffic that exactly matches its configuration. The provisioned capacity must be attached to the correct function version or alias, the traffic must be routed through that alias, and the request volume must stay within the provisioned limit. Any mismatch—version changes during deployment, traffic exceeding provisioned capacity, or incorrect alias routing—causes requests to fall back to on-demand execution with full cold start latency.

Understanding the interaction between aliases, versions, provisioned concurrency allocation, and traffic routing is critical for ensuring consistent low-latency performance. Provisioned concurrency is not a global setting; it's bound to specific function versions and requires ongoing configuration management as functions are updated and deployed.

Symptoms

When Lambda cold starts persist despite provisioned concurrency, you will observe these symptoms:

  • Latency spikes continue appearing after enabling provisioned concurrency
  • CloudWatch metrics show ProvisionedConcurrencySpilloverInvocations is non-zero
  • X-Ray traces reveal Init Duration for some requests
  • New deployments reintroduce cold starts even though alias name remains unchanged
  • Function invocation duration histogram shows both fast (warm) and slow (cold) outliers
  • API Gateway integration latency varies unpredictably
  • ProvisionedConcurrencyInvocations metric is lower than total invocations

CloudWatch metrics showing spillover:

```bash aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name ProvisionedConcurrencySpilloverInvocations \ --dimensions Name=FunctionName,Value=my-function Name=Resource,Value=my-function:prod \ --start-time 2026-04-10T07:30:00Z \ --end-time 2026-04-10T08:30:00Z \ --period 60 \ --statistics Sum

# Output showing spillover: { "Datapoints": [ {"Timestamp": "2026-04-10T07:35:00Z", "Sum": 45.0}, {"Timestamp": "2026-04-10T07:40:00Z", "Sum": 120.0} ] } # Spillover > 0 means cold starts occurring ```

Lambda logs showing initialization:

bash
INIT_START Runtime Version: python:3.11
INIT_DURATION: 850ms
# This indicates cold start despite provisioned concurrency

X-Ray trace showing cold start segments:

json
{
  "segments": [
    {
      "name": "my-function",
      "metadata": {
        "init_duration": 850,
        "cold_start": true
      }
    }
  ]
}

Common Causes

Several factors cause cold starts even with provisioned concurrency:

  1. 1.Provisioned concurrency attached to wrong alias/version: Traffic routes through an alias that isn't the one with provisioned capacity. Deployments may update alias routing without updating provisioned concurrency.
  2. 2.Traffic exceeds provisioned capacity: Request volume surpasses the allocated provisioned concurrency, causing spillover to on-demand execution. This happens during traffic spikes or insufficient capacity planning.
  3. 3.Alias points to new version after deployment: When a new version is published and the alias updated, the provisioned concurrency configuration may remain on the old version until explicitly reassigned.
  4. 4.Heavy initialization code: Even with provisioned concurrency, heavy initialization outside the handler function delays environment readiness. Large dependency imports, database connections, and configuration loading contribute to init time.
  5. 5.Scaling policy too slow: If provisioned concurrency uses target-tracking scaling, the policy may not respond quickly enough to sudden traffic increases, causing spillover during ramp-up.
  6. 6.Reserved concurrency competing: Reserved concurrency limits total function capacity, which may restrict provisioned concurrency allocation.
  7. 7.SnapStart not enabled: For Java Lambda functions, SnapStart (init snapshotting) can further reduce cold starts but requires explicit enablement alongside provisioned concurrency.
  8. 8.Multiple aliases with split traffic: Weighted alias routing splits traffic between versions, but provisioned concurrency may not cover all weighted targets.

Step-by-Step Fix

Follow these steps to diagnose and resolve provisioned concurrency cold start issues:

Step 1: Verify provisioned concurrency configuration

Check current provisioned concurrency settings:

```bash # Get provisioned concurrency for function aws lambda get-provisioned-concurrency-config \ --function-name my-function \ --qualifier prod

# Expected output: { "status": "READY", "allocatedProvisionedConcurrentExecutions": 10, "availableProvisionedConcurrentExecutions": 10 }

# If status is FAILED or allocations are 0, configuration is not applied ```

Step 2: Verify alias routing

Confirm the alias points to the correct version:

```bash # Get alias configuration aws lambda get-alias \ --function-name my-function \ --name prod

# Output: { "AliasArn": "arn:aws:lambda:region:account:function:my-function:prod", "FunctionVersion": "42", "Description": "Production alias" }

# Now check if provisioned concurrency is on this version aws lambda get-provisioned-concurrency-config \ --function-name my-function \ --qualifier prod

# Ensure qualifier matches the alias traffic is routed through ```

Step 3: Check invocation routing

Verify traffic reaches the provisioned alias:

```bash # If using API Gateway, check integration configuration aws apigateway get-integration \ --rest-api-id api-id \ --resource-id resource-id \ --http-method POST

# Lambda URI should include alias: # "uri": "arn:aws:lambda:region:account:function:my-function:prod"

# Wrong configuration (uses $LATEST instead): # "uri": "arn:aws:lambda:region:account:function:my-function"

# For Lambda invoke directly, ensure qualifier is used aws lambda invoke \ --function-name my-function \ --invocation-type RequestResponse \ --qualifier prod \ payload.json response.json ```

Step 4: Check spillover metrics

Monitor spillover invocations:

```bash # Get spillover metric aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name ProvisionedConcurrencySpilloverInvocations \ --dimensions Name=FunctionName,Value=my-function \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 60 \ --statistics Sum

# Also check provisioned invocations aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name ProvisionedConcurrencyInvocations \ --dimensions Name=FunctionName,Value=my-function \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 60 \ --statistics Sum

# If Spillover > 0, capacity is insufficient ```

Step 5: Update provisioned concurrency on deployment

Ensure deployment process updates provisioned concurrency:

```bash # After publishing new version, update alias aws lambda update-alias \ --function-name my-function \ --name prod \ --function-version 43 # New version

# Immediately provision concurrency for new version aws lambda put-provisioned-concurrency-config \ --function-name my-function \ --qualifier prod \ --provisioned-concurrent-executions 10

# Wait for provisioned concurrency to be ready aws lambda wait provisioned-concurrency-ready \ --function-name my-function \ --qualifier prod ```

Step 6: Increase provisioned capacity

Scale provisioned concurrency to match traffic:

```bash # Check current invocation rate aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name Invocations \ --dimensions Name=FunctionName,Value=my-function \ --start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 3600 \ --statistics Sum \ --output table

# Peak invocation rate determines needed capacity # Provision slightly above peak for safety margin

aws lambda put-provisioned-concurrency-config \ --function-name my-function \ --qualifier prod \ --provisioned-concurrent-executions 20 # Increased from 10 ```

Step 7: Configure scaling policy

Add automatic scaling for traffic variations:

```bash # Create target tracking scaling policy aws application-autoscaling register-scalable-target \ --service-namespace lambda \ --resource-id function:my-function:prod \ --scalable-dimension lambda:function:ProvisionedConcurrency \ --min-capacity 10 \ --max-capacity 50

aws application-autoscaling put-scaling-policy \ --service-namespace lambda \ --scalable-dimension lambda:function:ProvisionedConcurrency \ --policy-name provisioned-scaling \ --policy-type TargetTrackingScaling \ --resource-id function:my-function:prod \ --target-tracking-scaling-policy-configuration '{ "TargetValue": 70.0, "PredefinedMetricSpecification": { "PredefinedMetricType": "LambdaProvisionedConcurrencyUtilization" } }' ```

Step 8: Optimize initialization code

Reduce handler-less initialization:

```python # WRONG: Heavy imports at module level import pandas as pd import numpy as np from heavy_library import BigClass

def handler(event, context): # Handler code pass

# CORRECT: Lazy imports in handler def handler(event, context): import pandas as pd # Only import when needed # Handler code

# CORRECT: Initialize connection once, reuse import boto3 s3_client = boto3.client('s3') # Lightweight

def handler(event, context): # Use pre-initialized client s3_client.list_buckets() ```

Verification

After fixing configuration, verify cold starts are eliminated:

```bash # Check provisioned concurrency status aws lambda get-provisioned-concurrency-config \ --function-name my-function \ --qualifier prod

# Expected: status READY, allocated > 0, available > 0

# Monitor spillover over time aws cloudwatch get-metric-statistics \ --namespace AWS/Lambda \ --metric-name ProvisionedConcurrencySpilloverInvocations \ --dimensions Name=FunctionName,Value=my-function \ --start-time $(date -u -d '30 minutes ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --period 60 \ --statistics Sum

# Expected: Sum should be 0 or near-zero

# Test invocation latency aws lambda invoke \ --function-name my-function \ --qualifier prod \ payload.json response.json

# Check CloudWatch Logs for Init Duration # Expected: No INIT_START entries for provisioned invocations ```

X-Ray trace verification:

```bash # Analyze traces for cold start aws xray get-trace-summaries \ --start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --filter-expression 'service("my-function")'

# Cold starts should be minimal in trace metadata ```

Prevention

To prevent provisioned concurrency cold starts:

  1. 1.Automate alias-provisioned concurrency updates: Include provisioned concurrency configuration in deployment scripts.
bash
# Deployment script
#!/bin/bash
VERSION=$(aws lambda publish-function-version --function-name my-function --query 'Version' --output text)
aws lambda update-alias --function-name my-function --name prod --function-version $VERSION
aws lambda put-provisioned-concurrency-config --function-name my-function --qualifier prod --provisioned-concurrent-executions 10
aws lambda wait provisioned-concurrency-ready --function-name my-function --qualifier prod
  1. 1.Set capacity above peak traffic: Provision 20-30% above observed peak invocation rate.
  2. 2.Use scaling policies: Configure Application Auto Scaling for traffic variations.
bash
aws application-autoscaling put-scaling-policy \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration '{"TargetValue": 70.0}'
  1. 1.Monitor spillover metrics: Create CloudWatch alarms for spillover detection.
bash
aws cloudwatch put-metric-alarm \
  --alarm-name lambda-spillover-alert \
  --metric-name ProvisionedConcurrencySpilloverInvocations \
  --namespace AWS/Lambda \
  --dimensions Name=FunctionName,Value=my-function \
  --threshold 10 \
  --evaluation-periods 1 \
  --datapoints-to-alarm 1 \
  --comparison-operator GreaterThanThreshold
  1. 1.Keep initialization minimal: Move heavy imports and initialization into handler or use lazy loading.
  2. 2.Document alias and provisioned configuration: Maintain documentation linking aliases to provisioned capacity.
markdown
## Lambda Provisioned Concurrency
- Function: my-function
- Alias: prod -> Version: 42
- Provisioned: 20 concurrent executions
- Scaling: Target 70% utilization, min 10, max 50
  1. 1.Enable SnapStart for Java functions: Combine provisioned concurrency with SnapStart for Java.
bash
aws lambda update-function-configuration \
  --function-name my-java-function \
  --snap-start ApplySnapStartSetting=PublishedVersions

Related Articles

  • [AWS troubleshooting: Fix IAM Permission Denied - Complete Tro](fix-iam-permission-denied)
  • [AWS cloud troubleshooting: AWS ACM Certificate Pending Validation Because the](aws-acm-certificate-pending-validation-wrong-route53-zone)
  • [AWS cloud troubleshooting: AWS ALB Returns 502 Because the Target Closed the ](aws-alb-502-target-closed-connection-keepalive-timeout-mismatch)
  • [AWS cloud troubleshooting: Fix AWS ALB CreateListener TargetGroupNotFound Err](aws-alb-createlistener-targetgroupnotfound)
  • [AWS cloud troubleshooting: Fix Aws Alb Lambda 502 Bad Gateway Issue in AWS](aws-alb-lambda-502-bad-gateway)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "AWS cloud troubleshooting: AWS Lambda Still Cold Starting Even With Provision", "description": "Professional guide to fix AWS Lambda Still Cold Starting Even With Provisioned Concurrency. AWS cloud troubleshooting with step-by-step solutions. Learn best practices and prevention strategies.", "url": "https://www.fixwikihub.com/aws-lambda-cold-start-provisioned-concurrency-not-warm", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2026-01-23T02:46:00.463Z", "dateModified": "2026-01-23T02:46:00.463Z" } </script>