{"record":{"id":"4051eeb2fe85471b","repo":"pulumi/pulumi","slug":"unmarshalling-state-w","errorCode":null,"errorMessage":"unmarshalling state: %w","messagePattern":"unmarshalling state: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/secrets/cloud/manager.go","lineNumber":160,"sourceCode":"\tvar s cloudSecretsManagerState\n\terr := json.Unmarshal(state, &s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshalling cloud state: %w\", err)\n\t}\n\n\tinfo.SecretsProvider = s.URL\n\tinfo.EncryptedKey = base64.StdEncoding.EncodeToString(s.EncryptedKey)\n\treturn nil\n}\n\n// NewCloudSecretsManagerFromState deserialize configuration from state and returns a secrets\n// manager that uses the target cloud key management service to encrypt/decrypt a data key used for\n// envelope encryption of secrets values.\nfunc NewCloudSecretsManagerFromState(state json.RawMessage) (secrets.Manager, error) {\n\tvar s cloudSecretsManagerState\n\terr := json.Unmarshal(state, &s)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshalling state: %w\", err)\n\t}\n\n\t// We're emulating gocloud.dev's old behaviour here.  Pre v0.28.0 it used to have an inner wrapping, which\n\t// we keep for compatibility (see above). However the newer version expects this to be unwrapped, before\n\t// it's used. newCloudSecretsManager will manage that but we need to check here as well to handle the\n\t// #15329 regression.\n\tdataKey := s.EncryptedKey\n\tif strings.HasPrefix(s.URL, \"azurekeyvault://\") {\n\t\twrappedKey, err := base64.RawURLEncoding.DecodeString(string(dataKey))\n\t\tif err != nil {\n\t\t\t// https://github.com/pulumi/pulumi/issues/15329 resulted in some non-encoded keys being written\n\t\t\t// to state. This checks that case to see if there valid base64 data.\n\t\t\tfirstErr := err\n\t\t\t_, err := base64.StdEncoding.DecodeString(string(wrappedKey))\n\t\t\tif err != nil {\n\t\t\t\t// Wasn't valid base64 so probably just gibberish, return the first error we saw.\n\t\t\t\treturn nil, firstErr\n\t\t\t}","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/secrets/cloud/manager.go#L142-L178","documentation":"NewCloudSecretsManagerFromState reconstructs a cloud secrets manager from persisted JSON state. If the raw state cannot be unmarshalled into cloudSecretsManagerState (invalid JSON or wrong shape), this error wraps the failure. It's the read-path counterpart of the 'marshalling state' error at manager creation time.","triggerScenarios":"Loading a stack whose persisted secrets-manager state is corrupt, truncated, manually edited, or produced by an incompatible provider (e.g. passphrase salt text instead of the cloud state JSON).","commonSituations":"Hand-edited Pulumi.<stack>.yaml; git merge conflicts in stack config; migrating stacks between secrets providers; restoring partial backups; bug #15329-style regressions around the wrapped/unwrapped encrypted-key format.","solutions":["Restore Pulumi.<stack>.yaml (or the state blob) from version control or backup.","Re-initialize the secrets provider: `pulumi stack change-secrets-provider <new-provider>` (note existing secrets must be re-entered if the data key is lost).","Check the state matches {\"url\":\"...\",\"encryptedkey\":\"base64...\"} shape and fix formatting.","Verify you are not passing a passphrase-style salt string into the cloud manager constructor."],"exampleFix":"// before\nNewCloudSecretsManagerFromState(json.RawMessage(\"v1:salt:...\")) // wrong provider state\n\n// after\nNewCloudSecretsManagerFromState(json.RawMessage(`{\"url\":\"gcpkms://...\",\"encryptedkey\":\"BASE64==\"}`))","handlingStrategy":"validation","validationCode":"func isValidCloudSecretsState(state json.RawMessage) bool {\n    var s struct {\n        URL          string `json:\"url\"`\n        EncryptedKey []byte `json:\"encryptedkey\"`\n    }\n    return json.Unmarshal(state, &s) == nil && strings.Contains(s.URL, \"://\")\n}\n// only call NewCloudSecretsManagerFromState when isValidCloudSecretsState(state)","typeGuard":"func parseCloudState(state json.RawMessage) (*cloudSecretsManagerState, bool) {\n    var s cloudSecretsManagerState\n    if err := json.Unmarshal(state, &s); err != nil {\n        return nil, false\n    }\n    return &s, true\n}","tryCatchPattern":"mgr, err := NewCloudSecretsManagerFromState(state)\nif err != nil {\n    if strings.Contains(err.Error(), \"unmarshalling state\") {\n        return nil, fmt.Errorf(\"stack secrets state corrupt; restore Pulumi.<stack>.yaml or run 'pulumi stack change-secrets-provider': %w\", err)\n    }\n    return nil, err\n}","preventionTips":["Version-control Pulumi.<stack>.yaml so corrupt state can be restored.","Don't mix state blobs between different secrets-provider types.","Use `pulumi stack change-secrets-provider` for provider migrations instead of manual edits.","Back up stack config before upgrading CLI versions."],"tags":["json","deserialization","secrets","stack-config"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}