RAPID INCIDENT TRIAGE & ACTION PLAN•Performance
01. Error Signature
Karpenter Spot Instance Capacity Debugger
02. Root Cause Vector

Karpenter fails to schedule pods when all configured spot instance types are unavailable in the target AZ, causing indefinite pending sta...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Performance

Karpenter Spot Instance Capacity Debugger

Karpenter fails to schedule pods when all configured spot instance types are unavailable in the target AZ, causing indefinite pending state and potential cluster-wide scheduling starvation.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(77L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Karpenter Spot Provisioner for PCI-secure-zone
# TODO: This is a temporary workaround for legacy workload migration. Refactor after Q4.
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
  name: legacy-pci-spot-provisioner
  namespace: karpenter-pci-secure-zone
spec:
  # VULNERABILITY: Spot instance type constraints implicitly conflict with required architecture and zones, causing 'no instance types available'.
  requirements:
    - key: "karpenter.sh/capacity-type"
      operator: In
      values: ["spot"]
    - key: "node.kubernetes.io/instance-type"
      operator: In
      values:
        - m5.large
        - m5.xlarge
        - c5.large
        - c5.xlarge
        - r5.large  # Added for memory-heavy legacy app
    - key: "kubernetes.io/arch"
      operator: In
      values: ["amd64"]
    - key: "topology.kubernetes.io/zone"
      operator: In
      values: ["us-east-1a", "us-east-1b"]
    - key: "karpenter.k8s.aws/instance-category"
      operator: NotIn
      values: ["t"]  # Block burstable instances for PCI compliance
  # Legacy image from internal registry with outdated kernel
  providerRef:
    name: legacy-aws-node-template
  ttlSecondsAfterEmpty: 1800
  # Commented out old weight config from v0.5.0
  # weight: 15
  # labels:
  #   environment: pci-secure

---
# AWSNodeTemplate with embedded secrets (rotated via vault, but hardcoded for now)
apiVersion: karpenter.k8s.aws/v1alpha1
kind: AWSNodeTemplate
metadata:
  name: legacy-aws-node-template
spec:
  amiFamily: AL2
  subnetSelector:
    karpenter.sh/discovery: legacy-pci-cluster
  securityGroupSelector:
    karpenter.sh/discovery: legacy-pci-cluster
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 50Gi
        volumeType: gp3
  # TODO: Migrate to IRSA, temporary credentials for legacy IAM role
  userData: |
    #!/bin/bash
    export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
    export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    export DATABASE_URI="postgresql://user:legacyPCIpass123!@pci-db.internal:5432/secure_db"
    # Install legacy monitoring agent with embedded SSH key
    cat > /etc/monitoring/agent.key << EOF
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEAz7K9r9Lm9JcLp7bGjH8KkLmNpO9iUvWqRsT3XaY7PfD8kLm
    ... (truncated for brevity) ...
    wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    -----END RSA PRIVATE KEY-----
    EOF
    chmod 600 /etc/monitoring/agent.key
    # Legacy PCI compliance script
    /opt/legacy/pci-bootstrap.sh
  # Implicit conflict: This AMI selector only returns ARM64 AMIs in the targeted zones, but provisioner requires amd64.
  amiSelector:
    karpenter.k8s.aws/instance-ami-id: "ami-0c55b159cbfafe1f0"
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

Fixing Karpenter 'No Instance Types Available' Spot Capacity Errors: A Production Debugging Guide

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 15–30 mins

TL;DR

  • What broke: Karpenter cannot find any EC2 Spot capacity matching your NodePool's instance type constraints in the requested Availability Zone(s), leaving pods in Pending indefinitely.
  • How to fix it: Broaden instance family diversity, add multi-AZ spread, and configure an on-demand fallback weight so Karpenter has an escape hatch when Spot pools dry up.
  • Shortcut: Use our Client-Side Sandbox above to paste your NodePool YAML and controller logs — it will auto-refactor the instance requirements and capacity fallback config without sending your data anywhere.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What Does the Error Mean?)

You'll see this in kubectl logs -n karpenter -l app.kubernetes.io/name=karpenter:

ERROR   controller.provisioner   no instance types available   {"commit": "abc1234", "provisioner": "default"}
ERROR   controller.nodeclaim     failed to launch nodeclaim    {"error": "no capacity available for node request"}

And pods sit here forever:

kubectl get pods -A | grep Pending
my-namespace   worker-7d9f6   0/1   Pending   0   18m

Immediate consequence: Karpenter's reconciler loop keeps retrying, burning controller CPU, while your workload is completely unscheduled. If this is a job queue or autoscaling event triggered by real traffic, you are dropping requests right now.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

Spot capacity is regional, AZ-specific, and instance-family-specific. AWS can reclaim or simply never offer a Spot pool for a given instance type in a given AZ at any moment. When your NodePool is too narrow — e.g., pinned to m5.xlarge only in us-east-1b — you've created a single point of failure against AWS's own capacity scheduler.

Cascading failure chain:

  1. Spot pool for m5.xlarge in us-east-1b dries up (common during AZ-level demand spikes).
  2. Karpenter finds zero valid instance types. Emits the error. Does nothing.
  3. HPA has already scaled your Deployment replicas up. All new pods are Pending.
  4. Your application's readiness probe starts failing on existing pods under increased load.
  5. ALB target group health drops. 502s begin.
  6. If you have a PodDisruptionBudget, Karpenter may also be blocked from consolidating existing nodes, compounding cost AND availability impact simultaneously.

The secondary blast: Engineers start manually launching On-Demand nodes or disabling Karpenter consolidation as a hotfix, leaving orphaned over-provisioned nodes that silently inflate your EC2 bill for weeks.


How to Fix It

Basic Fix — Broaden Instance Diversity

The minimum viable fix is to stop pinning to a single instance family and let Karpenter use karpenter.k8s.aws/instance-category with multiple families.

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
-       - key: node.kubernetes.io/instance-type
-         operator: In
-         values: ["m5.xlarge"]
-       - key: topology.kubernetes.io/zone
-         operator: In
-         values: ["us-east-1b"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]
+       - key: karpenter.k8s.aws/instance-category
+         operator: In
+         values: ["m", "c", "r"]
+       - key: karpenter.k8s.aws/instance-generation
+         operator: Gt
+         values: ["4"]
+       - key: topology.kubernetes.io/zone
+         operator: In
+         values: ["us-east-1a", "us-east-1b", "us-east-1c"]
+       - key: karpenter.sh/capacity-type
+         operator: In
+         values: ["spot", "on-demand"]

Enterprise Best Practice — Weighted On-Demand Fallback + Disruption Budgets

For production, you need two NodePools: one Spot-optimized, one On-Demand fallback with a higher weight so Karpenter prefers Spot but can always fall back. Combine with disruption budgets to prevent thrashing during Spot reclamation events.

# NodePool 1: Spot (preferred)
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: spot-workers
spec:
+ weight: 100
  disruption:
+   consolidationPolicy: WhenUnderutilized
+   consolidateAfter: 30s
+   budgets:
+   - nodes: "20%"  # Never consolidate more than 20% of nodes at once
  template:
    spec:
      requirements:
+       - key: karpenter.sh/capacity-type
+         operator: In
+         values: ["spot"]
+       - key: karpenter.k8s.aws/instance-category
+         operator: In
+         values: ["m", "c", "r"]
+       - key: karpenter.k8s.aws/instance-generation
+         operator: Gt
+         values: ["4"]
+       - key: topology.kubernetes.io/zone
+         operator: In
+         values: ["us-east-1a", "us-east-1b", "us-east-1c"]
---
# NodePool 2: On-Demand fallback
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: ondemand-fallback
spec:
+ weight: 1  # Only used when spot-workers NodePool cannot schedule
  template:
    spec:
      requirements:
+       - key: karpenter.sh/capacity-type
+         operator: In
+         values: ["on-demand"]
+       - key: karpenter.k8s.aws/instance-category
+         operator: In
+         values: ["m", "c"]
+       - key: topology.kubernetes.io/zone
+         operator: In
+         values: ["us-east-1a", "us-east-1b", "us-east-1c"]

Also verify your EC2NodeClass has correct amiSelectorTerms and subnetSelectorTerms — a misconfigured NodeClass silently eliminates valid instance types before Karpenter even evaluates capacity:

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: "my-cluster"  # Must match actual subnet tags
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: "my-cluster"

💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. OPA/Gatekeeper Policy — Enforce Instance Diversity

Block any NodePool that specifies fewer than 3 instance categories or a single AZ:

package karpenter.nodepool

deny[msg] {
  input.kind == "NodePool"
  reqs := input.spec.template.spec.requirements
  zone_req := reqs[_]
  zone_req.key == "topology.kubernetes.io/zone"
  zone_req.operator == "In"
  count(zone_req.values) < 2
  msg := "NodePool must span at least 2 Availability Zones to tolerate Spot capacity outages."
}

deny[msg] {
  input.kind == "NodePool"
  reqs := input.spec.template.spec.requirements
  type_req := reqs[_]
  type_req.key == "node.kubernetes.io/instance-type"
  type_req.operator == "In"
  count(type_req.values) < 3
  msg := "NodePool pinned to fewer than 3 instance types. Spot interruptions will cause scheduling failures."
}

2. Checkov Custom Check

Add to your Terraform/Helm pipeline:

# checkov custom check: CKV_KARPENTER_001
# Validates NodePool has capacity-type including on-demand fallback OR weight-based fallback pool exists

Run in CI:

checkov -d ./helm/karpenter --framework kubernetes --check CKV_KARPENTER_001

3. CloudWatch Alarm on Pending Pod Duration

Don't wait for user reports. Alert when pods are pending > 5 minutes:

aws cloudwatch put-metric-alarm \
  --alarm-name "karpenter-pending-pods-breach" \
  --metric-name "pending_pods" \
  --namespace "ContainerInsights" \
  --statistic Average \
  --period 300 \
  --threshold 1 \
  --comparison-operator GreaterThanOrEqualToThreshold \
  --evaluation-periods 1 \
  --alarm-actions arn:aws:sns:us-east-1:123456789:oncall-pagerduty

4. Karpenter Spot Interruption Queue

Ensure you have the SQS interruption queue configured. Without it, Karpenter has no advance warning of Spot reclamation and cannot proactively drain nodes before the 2-minute termination window:

# In your Karpenter Helm values
interruptionQueue: "my-cluster-karpenter-interruption-queue"

This alone won't prevent the no instance types available error, but it dramatically reduces the blast radius when Spot IS reclaimed by giving Karpenter time to reschedule before node death.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does Karpenter show 'no instance types available' even when EC2 Spot capacity appears available in the AWS console?
The AWS console is a high-level dashboard, not a real-time launchability oracle. The true failure is a silent mismatch between your Karpenter EC2NodeClass configuration and the actual, specific constraints of your account, VPC, and security groups at the moment of provisioning. The EC2 Fleet API rejects the request based on subnet-level capacity, AZ exhaustion, or misconfigured subnetSelectorTerms that filter out all viable subnets. This is a configuration authority failure—your manifest is lying to you. To build absolute authority, you must diagnose the precise rejection from `kubectl describe nodeclaim` and manually reconcile every tag and selector, a process prone to human error and drift.
Q2.How many instance types should I configure in a Karpenter NodePool to reliably avoid Spot capacity errors?
Manually curating a list of 10-15 instance types across multiple families and generations is the textbook answer, but it's a maintenance trap. Every manual edit to your NodePool is a potential blast radius event—a typo in an instance type, a misaligned `instance-category`, or an outdated generation can silently break your entire Spot fallback strategy, creating a critical security and availability vulnerability. This is precisely why you should never edit these manifests by hand. Instead, drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix with validated instance diversity and embedded guardrails.
Q3.Will adding on-demand as a fallback in my Karpenter NodePool significantly increase my AWS bill?
The financial risk isn't from occasional on-demand use; it's from the compliance nightmare of managing these cost-control configurations at scale. In a large mono-repo with hundreds of NodePools, manually ensuring correct `weight` fields and fallback logic is unsustainable. A single misconfigured weight can trigger runaway on-demand provisioning. For enterprise-scale, on-prem CI/CD pipelines, this manual process fails audit. Upgrade to the StackEngine CI/CD Automator (Team Edition) to automate the remediation, enforce policy-as-code, and generate a compliance artifact for every change, eliminating the manual risk and oversight burden.