エラーの概要
Terraform で 400 エラーが発生する場合、これはクラウドプロバイダーの API が「不正なリクエスト」と判定したことを意味します。HCL の構文自体は正しくても、リソース定義のパラメーター型や値がプロバイダーの期待形式と一致していない場合に起こります。terraform apply 実行時に最も頻繁に遭遇するエラーで、本来なら terraform plan で事前に検出すべき問題です。
実際のエラーメッセージ例
Error: error creating DB Instance: BadRequest: 400 Bad Request
on main.tf line 15, in resource "aws_db_instance" "example":
15: resource "aws_db_instance" "example" {
with aws_db_instance.example,
on main.tf line 15, in resource "aws_db_instance" "example":
15: resource "aws_db_instance" "example" {
Error: Error making API call: status code 400, message: invalid parameter value
$ terraform apply
Error: error creating resource: BadRequest: The request body is malformed
│
│ with module.vpc.aws_security_group.allow_ssh:
│ on vpc/main.tf line 42, in resource "aws_security_group" "allow_ssh":
│ 42: resource "aws_security_group" "allow_ssh" {
よくある原因と解決手順
原因 1:リソースパラメーターの型が不正
Terraform のプロバイダーが期待する型(文字列、数値、リスト等)と異なる型で値を指定すると、API リクエスト生成時に 400 エラーが発生します。特に、数値として指定すべきポート番号を文字列で渡したり、ブール値を文字列で指定したりするケースが多く見られます。
Before(エラーが起きるコード):
resource "aws_security_group" "example" {
name = "example-sg"
description = "Example security group"
ingress {
from_port = "80" # 型エラー:文字列ではなく数値であるべき
to_port = "443" # 型エラー
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
depends_on = true # 型エラー:ブール値ではなく string の list
}
After(修正後):
resource "aws_security_group" "example" {
name = "example-sg"
description = "Example security group"
ingress {
from_port = 80 # 数値として指定
to_port = 443 # 数値として指定
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
原因 2:必須パラメーターが不足している
プロバイダーが要求する必須パラメーターを定義していない場合、API リクエストが不完全なため 400 エラーが返されます。ドキュメントで「Required」と明記されているパラメーターは必ず指定する必要があります。
Before(エラーが起きるコード):
resource "aws_db_instance" "example" {
identifier = "mydb"
engine = "mysql"
# allocated_storage と instance_class が不足
db_name = "mydb"
username = "admin"
password = "password123"
}
After(修正後):
resource "aws_db_instance" "example" {
identifier = "mydb"
engine = "mysql"
allocated_storage = 20 # 必須パラメーター
instance_class = "db.t3.micro" # 必須パラメーター
db_name = "mydb"
username = "admin"
password = "password123"
}
原因 3:プロバイダーのバージョン変更による API 形式の不一致
プロバイダーのバージョンアップで API リクエスト形式が変わり、古い書き方が 400 エラーになる場合があります。特に deprecated パラメーター(廃止予定のパラメーター)の廃止や新しい必須パラメーターの追加が影響します。
Before(エラーが起きるコード):
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # 新バージョンプロバイダー
}
}
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
associate_public_ip_address = "true" # 古い書き方(文字列)
user_data = base64encode("#!/bin/bash\necho hello") # 非推奨形式
}
After(修正後):
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
associate_public_ip_address = true # ブール値として指定
user_data = "#!/bin/bash\necho hello" # 推奨形式
}
原因 4:terraform plan を実行していないまま apply を実行
terraform plan を先に実行すれば、多くの 400 エラーは事前に検出できます。それをスキップして直接 apply を実行すると、API 呼び出し時にエラーが顕在化します。
Before(エラーが起きるコード):
# plan を実行せずに直接 apply
terraform apply -auto-approve
# Error: error making API call: status code 400...
After(修正後):
# 必ず plan を先に実行
terraform plan
# plan に問題がなければ apply
terraform apply
ツール固有の注意点
Terraform の 400 エラーは、HCL の構文チェック(terraform validate)では検出されません。validate は HCL の文法チェックのみで、プロバイダー側の要件チェックは行わないためです。そのため必ず terraform plan で実際のリクエスト生成をシミュレートして、プロバイダーの要件に適合しているか確認する必要があります。
AWS、Azure、Google Cloud など、各クラウドプロバイダーの Terraform プロバイダーは定期的に更新されます。プロバイダーのバージョンを固定せずに version = ">= 5.0" のように範囲指定している場合、CI/CD パイプラインで異なるバージョンが使用される可能性があります。本番環境では version = "= 5.12.0" のように完全なバージョン指定を検討してください。
また、プロバイダーの公式ドキュメントには各リソースの「Argument Reference」(引数参照)セクションが必ず記載されています。そこで「Required」と「Optional」の区別、各パラメーターの型、デフォルト値を必ず確認しましょう。
それでも解決しない場合
- 詳細なログを出力する
TF_LOG=DEBUG terraform plan
TF_LOG=DEBUG terraform apply
生成されたログファイルから、実際に API に送信されるリクエスト形式を確認できます。
- terraform state を確認する
既存のリソースが部分的に作成されている場合、state ファイルが破損していないか確認してください。
terraform state list
terraform state show <resource_name>
- プロバイダードキュメントを再確認
各プロバイダーの公式ドキュメントで、該当リソースの最新仕様を確認してください。
- AWS Provider: https://registry.terraform.io/providers/hashicorp/aws/latest/docs
- Azure Provider: https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
- Google Cloud Provider: https://registry.terraform.io/providers/hashicorp/google/latest/docs
- プロバイダーのバージョン互換性を確認
terraform version
terraform providers
プロバイダーが最新でない場合、アップグレードを試みてください。
terraform init -upgrade
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。