{"record":{"id":"64ae0b1083a30f96","repo":"pulumi/pulumi","slug":"unmarshalling-passphrase-state-w","errorCode":null,"errorMessage":"unmarshalling passphrase state: %w","messagePattern":"unmarshalling passphrase state: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/secrets/passphrase/manager.go","lineNumber":127,"sourceCode":"\nfunc (sm *localSecretsManager) Decrypter() config.Decrypter {\n\tcontract.Assertf(sm.crypter != nil, \"decrypter not initialized\")\n\treturn sm.crypter\n}\n\nfunc (sm *localSecretsManager) Encrypter() config.Encrypter {\n\tcontract.Assertf(sm.crypter != nil, \"encrypter not initialized\")\n\treturn sm.crypter\n}\n\nfunc EditProjectStack(info *workspace.ProjectStack, state json.RawMessage) error {\n\tinfo.EncryptedKey = \"\"\n\tinfo.SecretsProvider = \"\"\n\n\tvar s localSecretsManagerState\n\terr := json.Unmarshal(state, &s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unmarshalling passphrase state: %w\", err)\n\t}\n\tinfo.EncryptionSalt = s.Salt\n\treturn nil\n}\n\nvar (\n\tlock  sync.Mutex\n\tcache map[string]secrets.Manager\n)\n\n// clearCachedSecretsManagers is used to clear the cache, for tests.\nfunc clearCachedSecretsManagers() {\n\tlock.Lock()\n\tdefer lock.Unlock()\n\tcache = nil\n}\n\n// getCachedSecretsManager returns a cached secret manager and true, or nil and false if not in the cache.","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/pulumi/pulumi/blob/793f7b2e160db4321fb7fb6b0607461e01cb251e/pkg/secrets/passphrase/manager.go#L109-L145","documentation":"EditDistributedState (or equivalent) for the passphrase secrets manager deserializes the persisted state JSON into localSecretsManagerState to recover the salt string for the workspace stack info. If the raw state is not valid JSON or doesn't match localSecretsManagerState's shape, this error wraps the json.Unmarshal failure.","triggerScenarios":"Calling the passphrase manager's edit-state function with a corrupt, truncated, or wrong-provider state blob (e.g. a cloud manager state JSON or plain salt text instead of {\"salt\":\"v1:...\"}).","commonSituations":"Hand-edited Pulumi.<stack>.yaml; git merge conflicts in stack config; copying state between stacks with different secrets providers; truncated file writes.","solutions":["Restore Pulumi.<stack>.yaml from version control or a backup.","Confirm the state is JSON of the form {\"salt\":\"v1:<base64>:<base64>\"} and fix its shape.","If unrecoverable, re-initialize the stack's secrets provider and re-enter secret values.","Route the state to the matching provider's edit function (cloud state should go to the cloud manager)."],"exampleFix":"// before\nEditProjectStack(info, json.RawMessage(\"v1:abc\")) // raw salt text, not JSON\n\n// after\nEditProjectStack(info, json.RawMessage(`{\"salt\":\"v1:abc:def==\"}`))","handlingStrategy":"validation","validationCode":"func isValidPassphraseState(state json.RawMessage) bool {\n    var probe struct {\n        Salt string `json:\"salt\"`\n    }\n    return json.Unmarshal(state, &probe) == nil && strings.HasPrefix(probe.Salt, \"v1:\")\n}\n// call EditProjectStack only if isValidPassphraseState(state)","typeGuard":"func asPassphraseState(state json.RawMessage) (*localSecretsManagerState, bool) {\n    var s localSecretsManagerState\n    if err := json.Unmarshal(state, &s); err != nil || !strings.HasPrefix(s.Salt, \"v1:\") {\n        return nil, false\n    }\n    return &s, true\n}","tryCatchPattern":"if err := EditProjectStack(info, state); err != nil {\n    if strings.Contains(err.Error(), \"unmarshalling passphrase state\") {\n        // restore config from version control or re-init secrets provider\n    }\n    return err\n}","preventionTips":["Keep stack config under version control for easy restoration.","Resolve git merge conflicts in Pulumi.<stack>.yaml by keeping a complete, valid state blob.","Don't pass cloud-provider state blobs to the passphrase manager's edit functions.","Validate JSON before writing state to disk."],"tags":["passphrase","json","deserialization","stack-config"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"793f7b2e160db4321fb7fb6b0607461e01cb251e","analyzedAt":"2026-08-31T09:36:43.099Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}