{"record":{"id":"b5f1c405837476ab","repo":"hashicorp/terraform","slug":"error-copying-state-from-the-previous-q-backend-t","errorCode":null,"errorMessage":"Error copying state from the previous %q backend to the newly configured\n%q backend:\n    %s\n\nThe state in the previous backend remains intact and unmodified. Please resolve\nthe error above and try again.","messagePattern":"Error copying state from the previous %q backend to the newly configured\n%q backend:\n    (.+?)\n\nThe state in the previous backend remains intact and unmodified\\. Please resolve\nthe error above and try again\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/meta_backend_migrate.go","lineNumber":457,"sourceCode":"\n\t\t// Confirm with the user whether we want to copy state over\n\t\tconfirm, err := confirmFunc(sourceState, destinationState, opts)\n\t\tif err != nil {\n\t\t\tlog.Print(\"[TRACE] backendMigrateState: error reading input, so aborting migration\")\n\t\t\treturn err\n\t\t}\n\t\tif !confirm {\n\t\t\tlog.Print(\"[TRACE] backendMigrateState: user cancelled at confirmation prompt, so aborting migration\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Confirmed! We'll have the statemgr package handle the migration, which\n\t// includes preserving any lineage/serial information where possible, if\n\t// both managers support such metadata.\n\tlog.Print(\"[TRACE] backendMigrateState: migration confirmed, so migrating\")\n\tif err := statemgr.Migrate(destinationState, sourceState); err != nil {\n\t\treturn fmt.Errorf(strings.TrimSpace(errBackendStateCopy),\n\t\t\topts.SourceType, opts.DestinationType, err)\n\t}\n\t// The backend is currently handled before providers are installed during init,\n\t// so requiring schemas here could lead to a catch-22 where it requires some manual\n\t// intervention to proceed far enough for provider installation. To avoid this,\n\t// when migrating to HCP Terraform backend, the initial JSON varient of state won't be generated and stored.\n\tif err := destinationState.PersistState(nil); err != nil {\n\t\treturn fmt.Errorf(strings.TrimSpace(errBackendStateCopy),\n\t\t\topts.SourceType, opts.DestinationType, err)\n\t}\n\n\t// And we're done.\n\treturn nil\n}\n\nfunc (m *Meta) backendMigrateEmptyConfirm(source, destination statemgr.Full, opts *backendMigrateOpts) (bool, error) {\n\tvar inputOpts *terraform.InputOpts\n\tif opts.DestinationType == \"cloud\" {","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/meta_backend_migrate.go#L439-L475","documentation":"Returned by backendMigrateState_s_s when statemgr.Migrate(destinationState, sourceState) at line 456 fails — the confirmed copy/merge of source state into the destination state manager errored. The message errBackendStateCopy stresses the SOURCE remains intact (migration is a copy), so re-running is safe once the destination issue is fixed.","triggerScenarios":"After confirmation and locking, the actual state-copy operation (which preserves lineage/serial) fails: destination write failure, lineage conflict that Migrate can't reconcile, state schema incompatibility between source and destination managers. Wrapped at line 457-458.","commonSituations":"Destination backend write permission missing; destination state has a conflicting lineage with the source (both non-empty with different lineage — though the non-empty confirm prompt usually precedes this); large state exceeding destination size limits; remote backend rejecting the state version payload.","solutions":["Read the inner %s for the Migrate-level failure (write error, lineage conflict, size limit).","Fix destination write permissions / capacity, then re-run 'terraform init' — source is unchanged.","If lineage conflicts, decide which state is authoritative and manually 'terraform state push' it after clearing the destination.","For size limits (e.g., remote backend), reduce state size or use a backend with higher limits.","Check destination backend logs for the rejected write payload."],"exampleFix":"// before: destination write denied mid-Migrate\n//   Error copying state: ... AccessDenied on PutObject\n// after: grant write and retry (source intact)\n//   (attach s3:PutObject policy)\n//   terraform init","handlingStrategy":"validation","validationCode":"# Verify destination write access + lineage compatibility before migrating.\naws s3api put-object --bucket \"$TF_DST_BUCKET\" --key \"$TF_DST_KEY.migrationprobe\" --body /dev/null >/dev/null \\\n  || { echo 'destination not writable'; exit 1; }\naws s3 rm \"s3://$TF_DST_BUCKET/$TF_DST_KEY.migrationprobe\"\n# Compare lineage if both states present:\nterraform state pull -state=/tmp/src.tfstate\n# inspect .lineage vs destination's lineage to anticipate conflicts","typeGuard":null,"tryCatchPattern":"# Detect Migrate-level copy failure; source is intact so a retry is safe after fixing dst.\nterraform init 2>/tmp/init.err || rc=$?\nif grep -q 'Error copying state' /tmp/init.err; then\n  echo 'State copy failed — source intact. Fix destination write/lineage and retry.' >&2\nfi\nexit ${rc:-0}","preventionTips":["Grant write on the destination state path before migrating.","Pre-check lineage conflicts (both non-empty with different lineage) and decide authoritative state.","Ensure destination can accept the state size (remote backend limits).","Back up destination state before overwrite-style migrations."],"tags":["backend","state-migration","state-copy","statemgr-migrate","destination-backend","write-error","terraform-init"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}