hashicorp/terraform · error

operation timed out

Error message

operation timed out

What it means

Returned by the cloud backend (cloud/backend_common.go:648) when the uploaded configuration version never reaches tfe.ConfigurationUploaded within the 60-iteration poll loop (backend_common.go:625-644). The backend uploads the config dir, then polls ConfigurationVersions.Read on planConfigurationVersionsPollInterval; if `uploaded` stays false it wraps a plain 'operation timed out' error via b.generalError with message 'Failed to upload configuration files'. Causes are server-side ingest lag, oversized config, or network interruption rather than an explicit timer.

Solutions

  1. Retry the operation — transient platform/network issues are the usual cause.
  2. Check the workspace's configuration-version status in the TFC/HCP UI for ingest errors.
  3. Shrink the upload with a .terraformignore excluding large/vendored files.
  4. Confirm network/proxy connectivity to the TFC/HCP hostname.
Defensive patterns

Strategy: retry

Try / catch

cv, err := b.cloudUploadConfig(...)
if err != nil && strings.Contains(err.Error(), "operation timed out") {
    // config version never reached ConfigurationUploaded; retry after backoff
    return retryWithBackoff()
}

Prevention

When it happens

Trigger: Running terraform plan/apply with the 'cloud' backend where the config-version upload HTTP call succeeds but TFE/HCP never marks the CV ConfigurationUploaded within the poll budget (cloud/backend_common.go:625-649).

Common situations: Large vendored directories exceeding server ingest speed. TFE/HCP platform slowness or partial outage. Proxies that complete uploads but interfere with subsequent status reads.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/a8e0b4f1f09411cc. Report an issue: GitHub.

Appendix: source

Thrown at internal/cloud/backend_common.go:648

		case <-cancelCtx.Done():
			log.Printf("[TRACE] backend/cloud: operation cancelled while waiting for configuration status")
			return nil, context.Canceled
		case <-time.After(planConfigurationVersionsPollInterval):
			log.Printf("[TRACE] backend/cloud: reading configuration status")
			cv, err = b.client.ConfigurationVersions.Read(stopCtx, cv.ID)
			if err != nil {
				return nil, b.generalError("Failed to retrieve configuration version", err)
			}

			if cv.Status == tfe.ConfigurationUploaded {
				uploaded = true
			}
		}
	}

	if !uploaded {
		return nil, b.generalError(
			"Failed to upload configuration files", errors.New("operation timed out"))
	}

	log.Printf("[TRACE] backend/cloud: configuration uploaded and ready")

	return cv, nil
}

func (b *Cloud) parseRunVariables(op *backendrun.Operation) ([]*tfe.RunVariable, error) {
	config, configDiags := op.ConfigLoader.LoadRootModule(op.ConfigDir)
	if configDiags.HasErrors() {
		return nil, fmt.Errorf("error loading config with snapshot: %w", configDiags.Errs()[0])
	}

	variables, varDiags := ParseCloudRunVariables(op.Variables, config.Variables)

	if varDiags.HasErrors() {
		return nil, varDiags.Err()
	}

View on GitHub (pinned to d32a084675)