{"record":{"id":"f6eb9c3356be11c8","repo":"hashicorp/terraform","slug":"can-t-serialize-backend-configuration-as-json-s","errorCode":null,"errorMessage":"Can't serialize backend configuration as JSON: %s","messagePattern":"Can't serialize backend configuration as JSON: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/meta_backend.go","lineNumber":1795,"sourceCode":"\t\tif err := stateLocker.Lock(sMgr, \"backend from plan\"); err != nil {\n\t\t\tdiags = diags.Append(fmt.Errorf(\"Error locking state: %s\", err))\n\t\t\treturn nil, diags\n\t\t}\n\t\tdefer stateLocker.Unlock()\n\t}\n\n\t// Store the metadata in our saved state location\n\ts := sMgr.State()\n\tif s == nil {\n\t\ts = workdir.NewBackendStateFile()\n\t}\n\ts.Backend = &workdir.BackendConfigState{\n\t\tType: c.Type,\n\t\tHash: uint64(cHash),\n\t}\n\terr := s.Backend.SetConfig(configVal, b.ConfigSchema())\n\tif err != nil {\n\t\tdiags = diags.Append(fmt.Errorf(\"Can't serialize backend configuration as JSON: %s\", err))\n\t\treturn nil, diags\n\t}\n\n\t// Verify that selected workspace exists in the backend.\n\tif opts.Init && b != nil {\n\t\terr := m.selectWorkspace(b)\n\t\tif err != nil {\n\t\t\tdiags = diags.Append(err)\n\n\t\t\t// FIXME: A compatibility oddity with the 'remote' backend.\n\t\t\t// As an awkward legacy UX, when the remote backend is configured and there\n\t\t\t// are no workspaces, the output to the user saying that there are none and\n\t\t\t// the user should create one with 'workspace new' takes the form of an\n\t\t\t// error message - even though it's happy path, expected behavior.\n\t\t\t//\n\t\t\t// Therefore, only return nil with errored diags for everything else, and\n\t\t\t// allow the remote backend to continue and write its configuration to state\n\t\t\t// even though no workspace is selected.","sourceCodeStart":1777,"sourceCodeEnd":1813,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/command/meta_backend.go#L1777-L1813","documentation":"After locking, Terraform serializes the chosen backend config into the cache file via s.Backend.SetConfig(configVal, b.ConfigSchema()). The wrapped %s is the JSON marshal/encode error. This indicates the config value (cty) could not be encoded against the backend's declared schema, normally a schema/cty mismatch rather than a user input error.","triggerScenarios":"s.Backend.SetConfig fails marshalling configVal to JSON per b.ConfigSchema(). Triggers: backend ConfigSchema is nil or malformed, configVal contains a type the JSON encoder rejects (e.g. an unhandled cty capsule type), or a version skew between the running Terraform and the backend implementation's schema.","commonSituations":"Using a third-party backend plugin whose schema is inconsistent with the config value produced; a Terraform build mismatch; very rarely, a config value with deeply nested/optional attributes the schema did not declare.","solutions":["Read the inner %s to identify which attribute/type failed to encode.","Update the backend (built-in or plugin) to a version whose schema matches this Terraform build.","Simplify the backend block to only documented, schema-declared attributes and remove experimental/extra fields.","If reproducible with a stock backend on the latest release, file a bug with the inner error and the backend type/version."],"exampleFix":"// before\nbackend \"foo\" {\n  unknown_attr = \"x\"  # not in backend schema -> encode mismatch\n}\n\n// after\nbackend \"foo\" {\n  # only schema-declared attributes\n  region = \"us-east-1\"\n}","handlingStrategy":"validation","validationCode":"// Ensure configVal matches the backend schema before SetConfig.\nfunc validateConfigAgainstSchema(configVal cty.Value, schema *configschema.Block) error {\n    if schema == nil { return fmt.Errorf(\"backend schema is nil\") }\n    // use cty/json transform to attempt encode; surface mismatch early\n    if _, err := json.Marshal(schema.ImpliedType().Value(configVal)); err != nil {\n        return fmt.Errorf(\"config does not match backend schema: %w\", err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := s.Backend.SetConfig(configVal, b.ConfigSchema()); err != nil {\n    if isJSONEncodingErr(err) {\n        diags = diags.Append(fmt.Errorf(\"backend config does not match schema (remove undocumented attrs / align backend version): %s\", err))\n    } else {\n        diags = diags.Append(fmt.Errorf(\"Can't serialize backend configuration as JSON: %s\", err))\n    }\n    return nil, diags\n}","preventionTips":["Use only attributes declared by the backend's documentation/schema.","Keep the Terraform/OpenTofu CLI version aligned with the backend/plugin version.","After upgrading a backend plugin, re-init and review schema changes."],"tags":["backend","schema","json","serialization","config"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}