Terraform Error Guide: 'Conflicting configuration arguments' — Remove the Mutually Exclusive Argument
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
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 planorterraform validatefails withConflicting configuration argumentsand the phraseonly 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,
planmay 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_blocksandsource_security_group_idon anaws_security_group_rule, orfilenameandsource_code_hash-style pairs elsewhere. - Inline blocks and standalone resources managing the same thing: inline
ingress/egressplusaws_security_group_rule; inlinerouteplusaws_route; inlineaws_iam_rolepolicy 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
aorbto 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 validatein 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_eachwhen 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.
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.