{"record":{"id":"043ef0677e069ca1","repo":"hashicorp/terraform","slug":"migrating-state-from-hcp-terraform-or-terraform-en","errorCode":null,"errorMessage":"Migrating state from HCP Terraform or Terraform Enterprise to another %s is \nyet implemented.\n\nPlease use the API to do this: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions","messagePattern":"Migrating state from HCP Terraform or Terraform Enterprise to another (.+?) is \nyet implemented\\.\n\nPlease use the API to do this: https://developer\\.hashicorp\\.com/terraform/cloud-docs/api-docs/state-versions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/meta_backend_migrate.go","lineNumber":619,"sourceCode":"\tcloudBackendDestination, destinationTFC := opts.Destination.(*cloud.Cloud)\n\n\tsourceWorkspaces, sourceSingleState, err := retrieveWorkspaces(opts.Source, opts.SourceType)\n\tif err != nil {\n\t\treturn err\n\t}\n\t// to be used below, not yet implemented\n\t// destinationWorkspaces, destinationSingleState\n\t_, _, err = retrieveWorkspaces(opts.Destination, opts.SourceType)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// from HCP Terraform to non-TFC backend\n\tif sourceTFC && !destinationTFC {\n\t\tdstWord := backendHumanName(opts.Destination)\n\t\t// From HCP Terraform to another backend. This is not yet implemented, and\n\t\t// we recommend people to use the HCP Terraform API.\n\t\treturn fmt.Errorf(\n\t\t\tstrings.TrimSpace(errTFCMigrateNotYetImplemented), dstWord)\n\t}\n\n\t// Everything below, by the above two conditionals, now assumes that the\n\t// destination is always HCP Terraform.\n\tsourceSingle := sourceSingleState || (len(sourceWorkspaces) == 1)\n\tif sourceSingle {\n\t\tif cloudBackendDestination.WorkspaceMapping.Strategy() == cloud.WorkspaceNameStrategy {\n\t\t\t// If we know the name via WorkspaceNameStrategy, then set the\n\t\t\t// destinationWorkspace to the new Name and skip the user prompt. Here the\n\t\t\t// destinationWorkspace is not set to `default` thereby we will create it\n\t\t\t// in HCP Terraform if it does not exist.\n\t\t\topts.destinationWorkspace = cloudBackendDestination.WorkspaceMapping.Name\n\t\t}\n\n\t\tcurrentWorkspace, err := m.Workspace()\n\t\tif err != nil {\n\t\t\treturn err","sourceCodeStart":601,"sourceCodeEnd":637,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/meta_backend_migrate.go#L601-L637","documentation":"When the source backend is HCP Terraform / Terraform Enterprise (cloud.Cloud) and the destination is a non-TFC backend type, Terraform does not implement an automated migration path. The backendMigrateTFC function detects this combination (sourceTFC && !destinationTFC) and returns this error directing users to the HCP Terraform state-versions API. This is a deliberate limitation, not a transient failure.","triggerScenarios":"Changing the terraform configuration from a `cloud {}` block to a different backend type (e.g., `backend \"s3\"`, `backend \"local\"`, `backend \"http\"`) and running `terraform init`. The source is identified as cloud.Cloud but the destination is not.","commonSituations":"Moving infrastructure management from HCP Terraform to a self-hosted backend, consolidating state into S3, switching from managed to local for testing, or organizational restructuring that changes where state is managed.","solutions":["Use `terraform state pull` to download the current state, then configure the new backend and run `terraform state push`","Use the HCP Terraform state-versions API (https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions) to export state for each workspace","Manually create the state file in the new backend after downloading it","Use `terraform init -reconfigure` after manually placing state in the destination backend to skip automated migration"],"exampleFix":"# before: switching from cloud to s3 backend triggers this error\nterraform init\n# after: manual migration path\nterraform state pull > terraform.tfstate\n# edit backend config to s3, then:\nterraform init -reconfigure\nterraform state push terraform.tfstate","handlingStrategy":"validation","validationCode":"// Detect cloud->non-cloud migration before running init\n// Shell: check if config changed from cloud{} to backend \"x\"\n//   grep -q 'cloud {' old_config.tf && grep -q 'backend \"' new_config.tf && echo \"UNSUPPORTED_MIGRATION\"\n//\n// Go-level: inspect source/destination backend types\nfunc isUnsupportedMigration(source, dest backend.Backend) bool {\n    _, sourceIsCloud := source.(*cloud.Cloud)\n    _, destIsCloud := dest.(*cloud.Cloud)\n    return sourceIsCloud && !destIsCloud\n}","typeGuard":"// Check if a backend is a cloud backend\nfunc isCloudBackend(b backend.Backend) bool {\n    _, ok := b.(*cloud.Cloud)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["Never switch directly from cloud{} to a non-cloud backend expecting automated migration — it is not implemented","Plan cloud-to-non-cloud migrations as a manual state pull/push workflow","Document the manual migration procedure for teams that may need to leave HCP Terraform","Test the pull/push workflow in a non-production environment first"],"tags":["backend","migration","hcp-terraform","not-implemented","cloud"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}