Terraform Error: 'Invalid combination of arguments' (ConflictsWith / ExactlyOneOf)
Fix Terraform's 'Invalid combination of arguments' error from ConflictsWith and ExactlyOneOf provider rules: find the mutually exclusive attributes and set exactly the right one.
- #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.
Exact Error Message
╷
│ Error: Invalid combination of arguments
│
│ with aws_instance.web,
│ on main.tf line 12, in resource "aws_instance" "web":
│ 12: ami = "ami-0abcd1234ef567890"
│
│ "ami": conflicts with launch_template.
╵
You may also see the mirror-image form when a provider requires exactly one of a set of arguments:
│ Error: Invalid combination of arguments
│
│ with aws_lb_listener.https,
│ on listener.tf line 20, in resource "aws_lb_listener" "https":
│ 20: resource "aws_lb_listener" "https" {
│
│ "default_action[0].forward": one of
│ `default_action[0].forward,default_action[0].redirect` must be specified.
What It Means
Providers declare relationships between arguments in their schema. ConflictsWith means two (or more) arguments are mutually exclusive and must not both be set. ExactlyOneOf means precisely one argument out of a group must be set — no more, no fewer. AtLeastOneOf and RequiredWith are related variants that produce the same error text.
Terraform validates these rules before it plans anything, so this is a configuration error you can fix entirely in HCL. The message always names the offending argument and the group it clashes with, which tells you exactly which attribute to remove or add.
Common Causes
- Setting two mutually exclusive arguments, e.g.
amiandlaunch_templateon the sameaws_instance. - Copying an example that used one style, then adding a second conflicting argument without removing the first.
- A
dynamicblock or conditional expression that emits both branches of anExactlyOneOfgroup. - Setting an argument to
nullor""expecting it to “unset” — an explicitly assigned empty value can still count as “set” for some schema rules. - A module that passes through variables which populate conflicting arguments downstream.
Diagnostic Commands
Run a validate to surface every combination error at once, without contacting any provider APIs:
terraform validate
Re-run the plan to see the resource address and line number:
terraform plan
Confirm which arguments the schema treats as conflicting or exclusive by reading the provider schema directly:
terraform providers schema -json | jq '.provider_schemas
| to_entries[].value.resource_schemas["aws_instance"].block.attributes
| keys'
For a quick view of the resource’s documented constraints, open the provider docs for that exact resource type and search for “Conflicts” or “exactly one”.
Step-by-Step Resolution
-
Read the message carefully. It names the argument (
"ami") and what it conflicts with (launch_template). That is the pair you must reconcile. -
Decide which single argument you actually want. For a
ConflictsWithpair, keep one and delete the other:
resource "aws_instance" "web" {
# Use a launch template OR a bare ami/instance_type — not both.
launch_template {
id = aws_launch_template.web.id
version = "$Latest"
}
# ami = "ami-0abcd1234ef567890" # removed
# instance_type = "t3.micro" # removed
}
- For an
ExactlyOneOfgroup, make sure exactly one branch is present:
resource "aws_lb_listener" "https" {
load_balancer_arn = aws_lb.app.arn
port = 443
protocol = "HTTPS"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
# Do NOT also add a redirect{} block here.
}
}
- If a conditional or
dynamicblock is generating the extra argument, gate it so only one path is ever set:
dynamic "redirect" {
for_each = var.mode == "redirect" ? [1] : []
content {
port = "443"
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
-
Remove any
= null/= ""assignments on the conflicting argument. Simply omit the argument instead of assigning an empty value. -
Re-validate and re-plan to confirm the error is gone:
terraform validate && terraform plan
Prevention
- Read the provider docs for the resource before adding arguments; the “Conflicts with” notes are listed per attribute.
- Omit unused arguments entirely rather than assigning
nullor empty strings. - Keep
dynamicblocks and ternaries producing a single, well-defined branch for exclusive groups. - Run
terraform validatein CI so combination errors fail fast, before any apply. - When refactoring from one style to another (bare
amitolaunch_template), delete the old arguments in the same change.
Related Errors
Unsupported argument— the argument name is wrong or not part of the schema, rather than conflicting.Missing required argument— a required attribute is absent, the opposite of an exclusive-group violation.Invalid combination of argumentsfromAtLeastOneOf— none of a required group is set; add one.Conflicting configuration arguments— the wording some providers use for the same underlying schema rule.
Frequently Asked Questions
Why does Terraform reject the config before contacting the cloud API? These rules live in the provider schema, so ConflictsWith/ExactlyOneOf are validated locally during plan. That is why terraform validate catches them offline.
Can I set the conflicting argument to null to keep it in the file? No — an explicit assignment can still register as “set” for schema validation. Comment it out or delete it instead of assigning null.
How do I know which arguments conflict? The error names them, and terraform providers schema -json plus the resource’s provider documentation list every conflicting and exclusive relationship. You can also draft the corrected block with a Terraform prompt to double-check the pairing.
What is the difference between ExactlyOneOf and AtLeastOneOf? ExactlyOneOf allows precisely one argument from the group; AtLeastOneOf allows one or more. Both raise “Invalid combination of arguments” when violated. For more provider-schema fixes, see the Terraform guides.
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.