Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for OpenTofu By James Joyner IV · · 8 min read Last reviewed Jul 2026

OpenTofu Error: 'Unsupported block type' blocks are not expected here

Quick answer

Fix OpenTofu's 'Unsupported block type: Blocks of type ... are not expected here' error: diagnose wrong nesting, argument-vs-block confusion, and provider schema mismatches.

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

Stuck on this OpenTofu error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Exact Error Message


│ Error: Unsupported block type

│   on main.tf line 12, in resource "aws_security_group" "web":
│   12:   ingress_rule {

│ Blocks of type "ingress_rule" are not expected here.

The block name in quotes changes with your config — you might see Blocks of type "setting" are not expected here or Blocks of type "lifecycle_rule" are not expected here — but the cause is always the same.

What It Means

OpenTofu reports Unsupported block type when it encounters a nested block whose name is not part of the schema for the surrounding block. Every resource, data source, and provider has a fixed set of allowed nested blocks; anything else is rejected during parsing.

This is a static schema error. OpenTofu knows the exact shape of each resource from the provider’s schema, so a block that is misspelled, nested at the wrong level, or belongs to a different resource type is caught at tofu validate time before any plan runs.

Common Causes

  • A typo in the block name (ingress_rule instead of ingress).
  • Using an argument that should be written as name = value as if it were a block (or vice versa).
  • Nesting a block inside the wrong parent — for example, putting lifecycle inside another nested block.
  • Copying HCL for a different resource type that uses a similarly named block.
  • A provider version where the block was renamed, removed, or split into a separate resource.
  • Confusing a standalone resource (like aws_security_group_rule) with an inline block.

Diagnostic Commands

Validate the configuration to get the precise file, line, and rejected block name:

tofu validate

Dump the provider schema and list the nested block types the resource actually accepts:

tofu providers schema -json | \
  jq '.provider_schemas[].resource_schemas."aws_security_group".block.block_types | keys'

List the plain arguments too, so you can tell whether the name should be an argument instead of a block:

tofu providers schema -json | \
  jq '.provider_schemas[].resource_schemas."aws_security_group".block.attributes | keys'

Format the file to rule out a brace-nesting mistake that shifted the block:

tofu fmt -diff main.tf

Step-by-Step Resolution

  1. Read the error. It names the parent resource and the offending block. Confirm which of the two — wrong name or wrong nesting level — you are hitting.

  2. Check the accepted block types from the schema instead of guessing:

tofu providers schema -json | \
  jq '.provider_schemas."registry.opentofu.org/hashicorp/aws".resource_schemas."aws_security_group".block.block_types | keys'
  1. Fix the block name. For the example, ingress_rule should be ingress:
resource "aws_security_group" "web" {
  name   = "web"
  vpc_id = var.vpc_id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
  1. If the schema says the name is an argument, not a block, use = assignment instead:
# argument form, not a block
name = "web"
  1. If the block genuinely belongs to a separate resource, move it there. Security group rules can be managed as standalone resources:
resource "aws_security_group_rule" "web_https" {
  type              = "ingress"
  from_port         = 443
  to_port           = 443
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.web.id
}
  1. Re-validate to confirm the block is now accepted:
tofu validate
Success! The configuration is valid.

Prevention

  • Rely on editor autocomplete from the OpenTofu/Terraform language server so nested block names match the schema exactly.
  • Pin provider versions so a block rename in a new major version does not break parsing unexpectedly.
  • Run tofu validate in CI on every change to catch structural errors before merge.
  • When copying HCL between resource types, confirm the target resource actually supports the block; similar names do not guarantee similar schemas.
  • Read provider upgrade guides for blocks that were promoted to standalone resources.
  • Unsupported argument — an argument name the resource does not define (assignment, not a block).
  • Unsupported attribute — reading a non-existent attribute rather than declaring a block.
  • Missing required argument — a required argument inside an otherwise valid block was omitted.
  • Argument or block definition required — a syntax error where OpenTofu expected either but found neither.

Frequently Asked Questions

How do I know whether something should be a block or an argument? Check the provider schema: names under block_types are nested blocks written with braces, while names under attributes are arguments written with =.

Why does the same block work in one resource but not another? Each resource type has its own schema; a block valid for one resource is not automatically valid for a differently named resource, even within the same provider.

Can a provider upgrade cause this on config that used to validate? Yes. Blocks are sometimes renamed or split into standalone resources across major provider versions, so pinning versions avoids surprises.

Is this the same as an inline versus standalone rule choice? Often, yes — for example security group rules can be inline blocks or separate resources, and mixing the two forms triggers this error. For reusable troubleshooting prompts, browse the prompt library, and for more fixes see the OpenTofu guides.

Free download · 368-page PDF

Fixed it? Get 500 OpenTofu & 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.

Did this fix your issue?

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.