Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Terraform By James Joyner IV · · 9 min read

Terraform Error Guide: 'Conflicting configuration arguments' — Remove the Mutually Exclusive Argument

Quick answer

Fix Terraform 'Conflicting configuration arguments': two mutually exclusive fields are set together. Keep one, delete the other, split inline vs standalone.

  • #terraform
  • #iac
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

Conflicting configuration arguments is a provider-level validation error. Many resources define groups of arguments that are mutually exclusive — you may set one of them, but not more than one at the same time. The provider declares these with a ConflictsWith (or ExactlyOneOf) rule in its schema. When your configuration sets two members of such a group, Terraform rejects the resource during plan before any API call is made.

The literal message names the offending argument and the group it conflicts with:

Error: Conflicting configuration arguments

  with aws_security_group.web,
  on main.tf line 12, in resource "aws_security_group" "web":
  12:   ingress {

"ingress": only one of `ingress,ingress_block_all` can be set

A very common form of this error is the inline-vs-standalone conflict. Several AWS resources let you define nested rules inline or manage them with separate standalone resources — but never both. For example, aws_security_group’s inline ingress/egress blocks conflict with standalone aws_security_group_rule resources; aws_route_table’s inline route conflicts with aws_route; and inline IAM policy conflicts with aws_iam_role_policy_attachment. Mixing the two styles produces this error (or silent drift), so the provider forbids it.

Symptoms

  • terraform plan or terraform validate fails with Conflicting configuration arguments and the phrase only one of \a,b` can be set`.
  • The error cites a specific argument name and the group of arguments it conflicts with.
  • It appears right after you add a new argument to a resource that already had a related one set.
  • With inline-vs-standalone conflicts, plan may instead show endless churn (rules added and removed every apply) before you consolidate on one style.
  • The resource never reaches the provider API — this is a schema validation failure, not an API rejection.

Common Root Causes

  • Two mutually exclusive scalars set together: e.g., specifying both cidr_blocks and source_security_group_id on an aws_security_group_rule, or filename and source_code_hash-style pairs elsewhere.
  • Inline blocks and standalone resources managing the same thing: inline ingress/egress plus aws_security_group_rule; inline route plus aws_route; inline aws_iam_role policy plus separate policy resources.
  • Copy-paste from two examples: merging snippets that each used a different (valid) style, ending up with both.
  • Migrating styles halfway: moving from inline rules to standalone resources but leaving the inline blocks in place.
  • Overlapping optional arguments: the provider allows either a or b to express the same setting, and both were set.

Diagnostic Workflow

Validate to get the exact argument names and the conflict group:

terraform validate
terraform plan

Read the provider documentation for the resource to see which arguments are marked “Conflicts with”, then grep for both styles in your code:

# Are inline rules AND standalone rules both present for the same SG?
grep -rn 'ingress {\|egress {' *.tf
grep -rn 'aws_security_group_rule' *.tf

Here is a configuration that triggers the inline-vs-standalone conflict — the same security group is managed by both an inline ingress block and a standalone aws_security_group_rule:

resource "aws_security_group" "web" {
  name   = "web"
  vpc_id = var.vpc_id

  ingress {                              # inline rule...
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group_rule" "https" {   # ...and standalone rule = conflict
  type              = "ingress"
  security_group_id = aws_security_group.web.id
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}

The fix is to pick one style. The all-standalone version removes the inline block entirely:

resource "aws_security_group" "web" {
  name   = "web"
  vpc_id = var.vpc_id
  # no inline ingress/egress blocks
}

resource "aws_security_group_rule" "https" {
  type              = "ingress"
  security_group_id = aws_security_group.web.id
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
}

Example Root Cause Analysis

An engineer added rate-limited egress to an existing security group by pasting an aws_security_group_rule block from the provider docs, not realising the group already declared inline egress. The next plan failed:

Error: Conflicting configuration arguments

  with aws_security_group.web,
  on main.tf line 20, in resource "aws_security_group" "web":
  20:   egress {

"egress": only one of `egress,egress` cannot be combined with aws_security_group_rule

grep -rn 'egress {' *.tf showed the inline block on aws_security_group.web, and grep -rn 'aws_security_group_rule' *.tf showed the new standalone rule targeting the same security_group_id. The provider forbids managing the same group both ways because the two would fight each other on every apply. The team standardised on standalone aws_security_group_rule resources (easier to add per-rule with for_each), deleted the inline ingress/egress blocks, and re-ran terraform plan cleanly. Root cause: mixing the inline and standalone rule-management styles on one security group.

Prevention Best Practices

  • Pick one style per resource — either inline blocks or standalone rule resources — and document the choice so contributors do not mix them.
  • Before adding a standalone aws_security_group_rule, aws_route, or policy-attachment resource, grep for existing inline blocks on the target resource.
  • Read the “Conflicts With” / “Exactly One Of” notes in the provider documentation when setting an argument you have not used before.
  • Run terraform validate in pre-commit and CI so conflicting arguments fail before merge.
  • When migrating from inline to standalone rules, remove the inline blocks in the same change that adds the standalone resources.
  • Prefer standalone rule resources with for_each when rules change often; prefer inline blocks for small, static rule sets — but never both.

Quick Command Reference

# Surface the exact conflicting arguments
terraform validate

# Detect mixed inline + standalone management
grep -rn 'ingress {\|egress {' *.tf
grep -rn 'aws_security_group_rule\|aws_route\b' *.tf

# Re-plan after removing one side of the conflict
terraform plan

# If you removed inline blocks that were already applied, target-plan to preview
terraform plan -target=aws_security_group.web

Conclusion

Conflicting configuration arguments means a resource has two mutually exclusive arguments set at once, and the provider allows only one. The message spells out the group — only one of \a,b` can be set— so the fix is simply to keep one argument and delete the other. The most frequent trigger is mixing inline nested blocks (likeingress/egressorroute) with standalone resources (aws_security_group_rule, aws_route) that manage the same thing; choose a single style and remove the other. A terraform validate` gate and a quick grep for both styles before adding rules keep this conflict out of your plans.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.