This error occurs when Terraform tries to create a GCP resource (like Dataflow jobs) but the required API hasn't been enabled in your Google Cloud project. The fix is to explicitly enable the API using the google_project_service resource in Terraform or via gcloud CLI.
When you deploy infrastructure to Google Cloud Platform using Terraform, the GCP APIs that your resources depend on must be explicitly enabled in your project. Google Cloud uses API services to control access and billing for different functionalities. The "Error 400: API is not enabled" error occurs when Terraform attempts to call a GCP API that hasn't been activated in your project. For example, creating a Dataflow job requires the "dataflow.googleapis.com" API to be enabled. Without this, the Google API servers reject the request with a 400 error (bad request). This is a safety feature: users must intentionally enable each API they plan to use. Some APIs have dependencies on other APIs. When you enable one, its dependencies are often enabled automatically, but not always. The error typically manifests as: - `Error: googleapi: Error 400: Dataflow API is not enabled` - `Error: googleapi: Error 403: Permission denied` (when checking if API is enabled) - API name varies depending on what service you're trying to use (Compute Engine, Cloud Storage, BigQuery, etc.)
The proper solution is to declare the API enablement in your Terraform configuration:
resource "google_project_service" "dataflow" {
project = var.gcp_project_id
service = "dataflow.googleapis.com"
disable_on_destroy = false
}Add the depends_on argument to ensure the API is enabled before creating resources:
resource "google_project_service" "dataflow" {
project = var.gcp_project_id
service = "dataflow.googleapis.com"
disable_on_destroy = false
}
resource "google_dataflow_job" "example" {
depends_on = [google_project_service.dataflow]
name = "my-job"
template_gcs_path = "gs://my-bucket/templates/template_file"
temp_gcs_location = "gs://my-bucket/tmp_dir"
# ... other configuration
}This ensures the API is enabled before Terraform attempts to create any resources that depend on it.
Different GCP services use different API names. If you don't know which API to enable, look at the error message. It usually tells you exactly which API is not enabled.
Common API names:
Compute Services:
- compute.googleapis.com - Compute Engine (VMs, firewalls, networks)
- container.googleapis.com - Google Kubernetes Engine (GKE)
- cloudrun.googleapis.com - Cloud Run
Data Services:
- dataflow.googleapis.com - Cloud Dataflow (Apache Beam)
- dataproc.googleapis.com - Cloud Dataproc (Hadoop/Spark)
- bigquery.googleapis.com - BigQuery
- pubsub.googleapis.com - Cloud Pub/Sub
Storage:
- storage-api.googleapis.com - Cloud Storage API
- storage.googleapis.com - Cloud Storage JSON API
Networking:
- servicenetworking.googleapis.com - Service Networking (VPC peering)
- compute.googleapis.com - Cloud VPN
Database:
- sqladmin.googleapis.com - Cloud SQL Admin
- firestore.googleapis.com - Firestore
Other:
- cloudkms.googleapis.com - Cloud Key Management Service (KMS)
- artifactregistry.googleapis.com - Artifact Registry
Visit the [Google Cloud API Library](https://console.cloud.google.com/apis/library) to find the service name for any API.
If your infrastructure needs multiple APIs, declare them all:
locals {
required_apis = [
"compute.googleapis.com",
"container.googleapis.com",
"servicenetworking.googleapis.com",
"cloudkms.googleapis.com",
]
}
resource "google_project_service" "required" {
for_each = toset(local.required_apis)
project = var.gcp_project_id
service = each.value
disable_on_destroy = false
}
resource "google_compute_instance" "example" {
depends_on = [google_project_service.required]
name = "example"
machine_type = "e2-medium"
# ... other configuration
}This declares all APIs as dependencies, ensuring they're all enabled before any resources are created.
If you need to enable the API before running Terraform (e.g., in a CI/CD pipeline), use the gcloud CLI:
gcloud services enable dataflow.googleapis.com --project=MY_PROJECT_IDTo enable multiple APIs:
gcloud services enable \
compute.googleapis.com \
container.googleapis.com \
servicenetworking.googleapis.com \
--project=MY_PROJECT_IDIn a CI/CD pipeline, add this as a setup step before running terraform apply:
# GitHub Actions example
- name: Enable GCP APIs
run: |
gcloud services enable dataflow.googleapis.com
gcloud services enable compute.googleapis.com
env:
GOOGLE_CLOUD_PROJECT: ${{ secrets.GCP_PROJECT_ID }}However, the Terraform approach (google_project_service) is recommended because it's declarative and tracks API enablement as infrastructure.
The disable_on_destroy attribute controls whether Terraform disables the API when you destroy the resource:
Set to `false` (recommended):
resource "google_project_service" "dataflow" {
service = "dataflow.googleapis.com"
disable_on_destroy = false # Keep API enabled after terraform destroy
}This is safer because disabling an API can break other applications or infrastructure in the same project that depend on it.
Set to `true` (advanced use only):
resource "google_project_service" "temporary" {
service = "compute.googleapis.com"
disable_on_destroy = true # Disable API when terraform destroy is run
}Only use true if this is temporary test infrastructure and you're certain nothing else uses this API in the project.
To manually check if an API is enabled:
1. Go to the [Google Cloud Console](https://console.cloud.google.com)
2. Select your project from the dropdown at the top
3. Navigate to APIs & Services > Dashboard
4. Click + Enable APIs and Services
5. Search for the API name (e.g., "Dataflow")
6. Click the service and click Enable
Or use gcloud to list enabled APIs:
gcloud services list --enabled --project=MY_PROJECT_ID | grep dataflowIf you see the API listed, it's enabled. If not:
gcloud services enable dataflow.googleapis.com --project=MY_PROJECT_IDThe service account or user running Terraform needs the "Service Usage Admin" IAM role to enable APIs.
Check current permissions:
gcloud projects get-iam-policy MY_PROJECT_ID --flatten="bindings[].members" \
--format="table(bindings.role)" --filter="bindings.members:serviceAccount:terraform@*"Grant the role:
# For a service account
gcloud projects add-iam-policy-binding MY_PROJECT_ID \
--member="serviceAccount:terraform@MY_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/serviceusage.serviceUsageAdmin"
# For a user
gcloud projects add-iam-policy-binding MY_PROJECT_ID \
--member="user:[email protected]" \
--role="roles/serviceusage.serviceUsageAdmin"The error message might say "Permission denied" (403) instead of "not enabled" (400) if this is the issue. Both require checking service account permissions.
### API Dependencies
Some GCP APIs automatically enable their dependencies. For example:
- Enabling container.googleapis.com (GKE) auto-enables:
- compute.googleapis.com (Compute Engine)
- container.googleapis.com (needed for clusters)
- Enabling cloud-build.googleapis.com (Cloud Build) auto-enables:
- storage-api.googleapis.com (Cloud Storage)
If you declare all dependencies explicitly in Terraform, you avoid relying on this auto-enablement, making your infrastructure more predictable.
### Organization Policy Constraints
If your organization has disabled certain APIs via Organization Policy, you won't be able to enable them, even with the correct IAM roles. You'll see errors like:
Error: googleapi: Error 403: Policy name [constraints/serviceusage.restrictedApi]
Check with your organization administrator to see if the API is restricted. They may need to update the policy constraint to allow it.
### API Enablement Takes Time
After enabling an API, it may take a few seconds to become active. If you run terraform apply immediately after enabling via gcloud CLI, you might still see "API not enabled" errors. The Terraform google_project_service resource handles this automatically with built-in retry logic.
### Multiple Projects or Environments
In a multi-environment setup, you might need to enable different APIs in different projects:
resource "google_project_service" "apis" {
for_each = toset(var.required_apis)
project = var.gcp_project_id # Variable per environment
service = each.value
disable_on_destroy = false
}Use different terraform.tfvars files per environment to specify different APIs or project IDs.
### Debugging with Terraform Debug
If you're unsure why an API isn't enabling, enable debug logging:
export TF_LOG=DEBUG
terraform applyThe logs will show the actual API calls Terraform is making and any error responses from Google.
Error: Error rendering template: template not found
How to fix "template not found" error in Terraform
Error: Error generating private key
How to fix 'Error generating private key' in Terraform
Error creating Kubernetes Service: field is immutable
How to fix "field is immutable" errors in Terraform
Error: Error creating local file: open: permission denied
How to fix "Error creating local file: permission denied" in Terraform
Error: line endings have changed from CRLF to LF
Line endings have changed from CRLF to LF in Terraform