{"record":{"id":"9ff16ebf82069d15","repo":"hashicorp/terraform","slug":"can-t-serialize-backend-configuration-as-json-s-9ff16e","errorCode":null,"errorMessage":"Can't serialize backend configuration as JSON: %s","messagePattern":"Can't serialize backend configuration as JSON: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/state_migrate.go","lineNumber":194,"sourceCode":"\t\t\tmigrateOpts.DestinationType = rootMod.Backend.Type\n\t\t\tmigrateOpts.Destination = dstB\n\n\t\t\t// Capture details of the destination backend for updating the backend state file after a successful migration.\n\t\t\t_, cHash, bcDiags := c.backendConfig(&BackendOpts{\n\t\t\t\tBackendConfig: rootMod.Backend,\n\t\t\t})\n\t\t\tdiags = diags.Append(bcDiags)\n\t\t\tif bcDiags.HasErrors() {\n\t\t\t\tview.Diagnostics(diags)\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\tbsf.Backend = &workdir.BackendConfigState{\n\t\t\t\tType: rootMod.Backend.Type,\n\t\t\t\tHash: uint64(cHash),\n\t\t\t}\n\t\t\terr := bsf.Backend.SetConfig(dstConfig, dstB.ConfigSchema())\n\t\t\tif err != nil {\n\t\t\t\tdiags = diags.Append(fmt.Errorf(\"Can't serialize backend configuration as JSON: %s\", err))\n\t\t\t\tview.Diagnostics(diags)\n\t\t\t\treturn 1\n\t\t\t}\n\t\t}\n\t} else if rootMod.StateStore != nil {\n\t\t// Get single required_providers entry for state store provider.\n\t\tdstReq, dstReqDiags := c.getDestinationStateStoreProviderRequirements(rootMod.StateStore.ProviderAddr, rootMod.ProviderRequirements)\n\t\tdiags = diags.Append(dstReqDiags)\n\t\tif dstReqDiags.HasErrors() {\n\t\t\tview.Diagnostics(diags)\n\t\t\treturn 1\n\t\t}\n\n\t\t// Load any pre-existing destination provider lock file.\n\t\tvar lockfilePath string\n\t\tif args.DestinationLockFilePath != \"\" {\n\t\t\tlockfilePath = args.DestinationLockFilePath\n\t\t} else {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/command/state_migrate.go#L176-L212","documentation":"Thrown during `terraform state migrate` when capturing the destination backend config into the BackendStateFile: bsf.Backend.SetConfig(dstConfig, dstB.ConfigSchema()) fails. SetConfig marshals the cty config value to JSON via ctyjson.Marshal against the backend schema's ImpliedType; it errors when the value contains attributes/types not present in that schema. The %s is the underlying marshal error.","triggerScenarios":"Running `terraform state migrate` to a destination backend whose in-memory configuration value (dstConfig from backendInitFromConfig) does not match the schema returned by dstB.ConfigSchema(). Typically a backend schema/version mismatch, a malformed backend block, or a provider/backend that changed its schema between when the config was parsed and when SetConfig ran.","commonSituations":"Migrating between backend types (s3 -> azurerm, local -> cloud) with extra/unknown attributes; a backend plugin shipped a schema change; leftover deprecated attributes in the backend block; custom backend that advertises a narrower schema than the config supplies.","solutions":["Inspect the wrapped %s message: it names the exact attribute/type that failed to marshal against the backend schema.","Remove any backend-block attributes not accepted by the destination backend type (compare against that backend's docs).","Re-run `terraform init` for the destination backend so its schema is current.","If migrating backend types, edit the backend block to match the destination backend's required/optional attributes first."],"exampleFix":"# before - migrating to s3 with a cloud-only attribute\nterraform {\n  backend \"s3\" {\n    workspaces { name = \"dev\" } # not a valid s3 attribute\n  }\n}\n\n# after\nterraform {\n  backend \"s3\" {\n    bucket = \"tf-state\"\n    key    = \"dev/terraform.tfstate\"\n    region = \"us-east-1\"\n  }\n}","handlingStrategy":"validation","validationCode":"// validate a backend block against its schema before migrating.\n// Pseudocode: marshal the config value and unmarshal against the\n// destination backend's ConfigSchema() implied type.\nfunc validateBackendConfig(val cty.Value, schema *configschema.Block) error {\n    _, err := ctyjson.Marshal(val, schema.ImpliedType())\n    return err\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the backend block's attributes limited to those documented for that backend type.","Re-run `terraform init` after changing backend type so the schema is current.","Avoid carrying deprecated attributes when switching backend types.","Validate config with `terraform validate` before `terraform state migrate`."],"tags":["state-migrate","backend","schema","json"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}