# Creating Composite CloudWatch Alarms with Condition Logic and Missing Data Treatment

> Learn to create composite CloudWatch alarms using AND OR AT_LEAST logic and manage missing data to avoid INSUFFICIENT_DATA alerts. Aggregate metrics effectively.

- Repository: [Amazon Web Services/agent-toolkit-for-aws](https://github.com/aws/agent-toolkit-for-aws)
- Tags: how-to-guide
- Published: 2026-06-29

---

**Composite CloudWatch alarms aggregate multiple metric alarms using Boolean operators like `AND`, `OR`, and `AT_LEAST`, while explicit `treatMissingData` settings prevent false `INSUFFICIENT_DATA` states during gaps in telemetry.**

The Agent Toolkit for AWS provides comprehensive guidance for building robust observability stacks, including detailed patterns for creating composite CloudWatch alarms with proper condition logic and missing data treatment. Located in the `aws/agent-toolkit-for-aws` repository, the toolkit's reference documentation and TypeScript assets demonstrate how to combine metric states with Boolean rules while handling data gaps explicitly.

## How Composite Alarms Work

Composite alarms evaluate the states of underlying metric alarms using rule expressions. According to the reference documentation in [`skills/core-skills/aws-observability/references/alarms.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-observability/references/alarms.md), these alarms enable complex service-level health checks by combining multiple individual metrics into a single actionable state.

### Boolean Operators and Syntax

The toolkit supports four logical operators for alarm aggregation:

- **`AND`** – All referenced alarms must be in the **ALARM** state.
- **`OR`** – At least one referenced alarm must be **ALARM**.
- **`NOT`** – The referenced alarm must **NOT** be **ALARM** (must be OK or INSUFFICIENT_DATA).
- **`AT_LEAST(M, STATE, (a1, a2, …))`** – At least *M* of the listed alarms must be in the specified state. Percentages are valid, such as `AT_LEAST(50%, ALARM, (a1, a2, a3))`.

In CDK, the `CompositeAlarm` construct uses the `AlarmRule` helper to express these relationships. The `AlarmRule.anyOf`, `AlarmRule.allOf`, and `AlarmRule.not` methods map directly to the Boolean operators above.

### Account and Region Constraints

All underlying metric alarms and the composite alarm must reside in the same AWS account and Region. Cross-account or cross-region alarm aggregation is not supported in the current implementation.

## Missing Data Treatment Options

When metrics fail to publish datapoints during an evaluation period, CloudWatch requires explicit guidance on interpreting the gap. The `treatMissingData` parameter controls this behavior, and the toolkit strongly recommends explicitly setting this value for every alarm to avoid ambiguous states.

### The Four TreatMissingData Behaviors

| Value | Behavior | Use Case |
|-------|----------|----------|
| `missing` (default) | Missing data triggers **INSUFFICIENT_DATA** | EC2 stop/terminate actions |
| `notBreaching` | Missing data treated as OK (within threshold) | Error-count metrics where "no data = no errors" |
| `breaching` | Missing data treated as ALARM (violates threshold) | Heartbeat or health-check metrics |
| `ignore` | Current state remains unchanged | DynamoDB alarms (console overrides default) |

### Choosing the Right Policy

The default `missing` setting often leads to unexpected **INSUFFICIENT_DATA** states that can mask genuine issues. For error-rate metrics, use `notBreaching` to assume success when no data arrives. For heartbeat checks, use `breaching` to treat silence as a failure. According to the source analysis, lines 60-62 of [`alarms.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/alarms.md) emphasize that explicit configuration prevents operational ambiguity.

## Implementation Patterns

The Agent Toolkit provides both conceptual documentation and executable code assets. The [`plugins/aws-core/skills/aws-observability/assets/alarm-template.ts`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-observability/assets/alarm-template.ts) file contains production-ready TypeScript implementations demonstrating the `CompositeAlarm` construct with `AlarmRule` helpers.

### CDK Implementation with AlarmRule

The following pattern creates individual metric alarms with explicit missing data handling, then combines them into a composite alarm:

```typescript
import {
  Alarm,
  ComparisonOperator,
  MathExpression,
  TreatMissingData,
  CompositeAlarm,
  AlarmRule,
  AlarmState,
} from 'aws-cdk-lib/aws-cloudwatch';
import { Duration } from 'aws-cdk-lib';

// Individual metric alarm with explicit missing data treatment
const errorRateAlarm = new Alarm(this, 'ErrorRateAlarm', {
  metric: new MathExpression({
    expression: 'IF(invocations > 0, errors * 100 / invocations, 0)',
    usingMetrics: {
      errors: fn.metricErrors({ period: Duration.minutes(1) }),
      invocations: fn.metricInvocations({ period: Duration.minutes(1) }),
    },
  }),
  threshold: 5,
  evaluationPeriods: 3,
  datapointsToAlarm: 2,
  comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
  treatMissingData: TreatMissingData.NOT_BREACHING,
});

const latencyAlarm = new Alarm(this, 'LatencyAlarm', {
  metric: fn.metricDuration({ statistic: 'p99', period: Duration.minutes(1) }),
  threshold: 3000,
  evaluationPeriods: 3,
  datapointsToAlarm: 2,
  comparisonOperator: ComparisonOperator.GREATER_THAN_THRESHOLD,
  treatMissingData: TreatMissingData.NOT_BREACHING,
});

// Composite alarm firing when either condition is unhealthy
const serviceHealthAlarm = new CompositeAlarm(this, 'ServiceHealth', {
  alarmRule: AlarmRule.anyOf(
    AlarmRule.fromAlarm(errorRateAlarm, AlarmState.ALARM),
    AlarmRule.fromAlarm(latencyAlarm, AlarmState.ALARM),
  ),
});

```

### CLI Configuration

Create metric alarms with explicit missing data handling via the AWS CLI:

```bash
aws cloudwatch put-metric-alarm \
  --alarm-name MyFunc-ErrorRate \
  --metrics '[
    {"Id":"errors","MetricStat":{"Metric":{"Namespace":"AWS/Lambda","MetricName":"Errors","Dimensions":[{"Name":"FunctionName","Value":"MyFunc"}]},"Period":60,"Stat":"Sum"},"ReturnData":false},
    {"Id":"invocations","MetricStat":{"Metric":{"Namespace":"AWS/Lambda","MetricName":"Invocations","Dimensions":[{"Name":"FunctionName","Value":"MyFunc"}]},"Period":60,"Stat":"Sum"},"ReturnData":false},
    {"Id":"error_rate","Expression":"IF(invocations > 0, errors * 100 / invocations, 0)","Label":"Error Rate %"}
  ]' \
  --threshold 5 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 3 \
  --datapoints-to-alarm 2 \
  --treat-missing-data notBreaching

```

Configure latency monitoring with the same missing data policy:

```bash
aws cloudwatch put-metric-alarm \
  --alarm-name MyFunc-Latency \
  --namespace AWS/Lambda \
  --metric-name Duration \
  --dimensions Name=FunctionName,Value=MyFunc \
  --extended-statistic p99 \
  --period 60 \
  --evaluation-periods 3 \
  --datapoints-to-alarm 2 \
  --threshold 3000 \
  --comparison-operator GreaterThanThreshold \
  --treat-missing-data notBreaching

```

### CloudFormation YAML

Define composite alarms in CloudFormation using the `AWS::CloudWatch::CompositeAlarm` resource type:

```yaml
Resources:
  ServiceHealthAlarm:
    Type: AWS::CloudWatch::CompositeAlarm
    Properties:
      AlarmName: ServiceHealth
      AlarmRule: |
        ALARM("ErrorRateAlarm") OR ALARM("LatencyAlarm")

```

## Limitations and Architecture

Understanding the constraints of composite alarms ensures proper operational design.

### Action Constraints

Composite alarms **cannot** trigger EC2 or Auto Scaling actions. Any remediation requiring instance termination, scaling, or recovery must be attached directly to the underlying metric alarms, not the composite alarm. This limitation is documented in [`alarms.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/alarms.md) at lines 33-34.

### Source Code Structure

The Agent Toolkit organizes alarm functionality across two primary locations:

- **[`skills/core-skills/aws-observability/references/alarms.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-observability/references/alarms.md)** – Conceptual documentation covering operators, missing data semantics, and CLI/CDK examples.
- **[`plugins/aws-core/skills/aws-observability/assets/alarm-template.ts`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-observability/assets/alarm-template.ts)** – Executable TypeScript asset containing the `CompositeAlarm` implementation with `AlarmRule` constructs.

These resources are consumed by the Agent Toolkit's LLM-driven agents to generate correct CloudFormation or CDK deployments on demand.

## Summary

- **Composite alarms** use Boolean operators (`AND`, `OR`, `NOT`, `AT_LEAST`) to aggregate multiple metric alarm states into a single health indicator.
- **Explicit `treatMissingData`** configuration is required to prevent false `INSUFFICIENT_DATA` states; choose `notBreaching` for error metrics, `breaching` for heartbeats, and `missing` only when EC2 actions are required.
- **Regional constraints** require all underlying alarms and the composite alarm to exist in the same AWS account and Region.
- **Action limitations** prevent composite alarms from triggering EC2 or Auto Scaling actions; attach these actions to individual metric alarms instead.
- **Implementation** follows the patterns in [`alarm-template.ts`](https://github.com/aws/agent-toolkit-for-aws/blob/main/alarm-template.ts) using `AlarmRule` helpers for CDK, or direct rule expressions for CloudFormation.

## Frequently Asked Questions

### How do I prevent a composite CloudWatch alarm from entering INSUFFICIENT_DATA when one metric stops reporting?

Set the `treatMissingData` parameter to `notBreaching` on the individual metric alarm. This treats missing datapoints as "within threshold" (OK), preventing the composite alarm from transitioning to `INSUFFICIENT_DATA` when telemetry gaps occur. Use this for error-rate or latency metrics where no data implies healthy behavior.

### Can composite CloudWatch alarms trigger EC2 Auto Scaling actions?

No. Composite alarms cannot trigger EC2 or Auto Scaling actions directly. You must attach scaling policies to the underlying metric alarms. The composite alarm is suitable for notifications and overall service health dashboards, while individual metric alarms handle infrastructure remediation.

### What is the difference between AlarmRule.anyOf and AlarmRule.allOf in CDK?

`AlarmRule.anyOf` implements the `OR` operator, triggering the composite alarm when at least one referenced alarm is in the `ALARM` state. `AlarmRule.allOf` implements the `AND` operator, requiring all referenced alarms to be in `ALARM` before the composite alarm fires. Both are available in the `aws-cdk-lib/aws-cloudwatch` module.

### How do I require at least 50% of my alarms to fire before triggering a composite alarm?

Use the `AT_LEAST` operator in your alarm rule expression: `AT_LEAST(50%, ALARM, (alarm1, alarm2, alarm3))`. In CloudFormation YAML, write the rule as `AT_LEAST(50%, ALARM("alarm1"), ALARM("alarm2"), ALARM("alarm3"))`. This creates a threshold-based composite alarm that tolerates partial failures without requiring complex CDK logic.