pulumi/pulumi · error

unmarshalling state: %w

Error message

unmarshalling state: %w

What it means

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.

Source

Thrown at pkg/secrets/cloud/manager.go:160

	var s cloudSecretsManagerState
	err := json.Unmarshal(state, &s)
	if err != nil {
		return fmt.Errorf("unmarshalling cloud state: %w", err)
	}

	info.SecretsProvider = s.URL
	info.EncryptedKey = base64.StdEncoding.EncodeToString(s.EncryptedKey)
	return nil
}

// NewCloudSecretsManagerFromState deserialize configuration from state and returns a secrets
// manager that uses the target cloud key management service to encrypt/decrypt a data key used for
// envelope encryption of secrets values.
func NewCloudSecretsManagerFromState(state json.RawMessage) (secrets.Manager, error) {
	var s cloudSecretsManagerState
	err := json.Unmarshal(state, &s)
	if err != nil {
		return nil, fmt.Errorf("unmarshalling state: %w", err)
	}

	// We're emulating gocloud.dev's old behaviour here.  Pre v0.28.0 it used to have an inner wrapping, which
	// we keep for compatibility (see above). However the newer version expects this to be unwrapped, before
	// it's used. newCloudSecretsManager will manage that but we need to check here as well to handle the
	// #15329 regression.
	dataKey := s.EncryptedKey
	if strings.HasPrefix(s.URL, "azurekeyvault://") {
		wrappedKey, err := base64.RawURLEncoding.DecodeString(string(dataKey))
		if err != nil {
			// https://github.com/pulumi/pulumi/issues/15329 resulted in some non-encoded keys being written
			// to state. This checks that case to see if there valid base64 data.
			firstErr := err
			_, err := base64.StdEncoding.DecodeString(string(wrappedKey))
			if err != nil {
				// Wasn't valid base64 so probably just gibberish, return the first error we saw.
				return nil, firstErr
			}

View on GitHub (pinned to 793f7b2e16)

Solutions

  1. Restore Pulumi.<stack>.yaml (or the state blob) from version control or backup.
  2. 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).
  3. Check the state matches {"url":"...","encryptedkey":"base64..."} shape and fix formatting.
  4. Verify you are not passing a passphrase-style salt string into the cloud manager constructor.

Example fix

// before
NewCloudSecretsManagerFromState(json.RawMessage("v1:salt:...")) // wrong provider state

// after
NewCloudSecretsManagerFromState(json.RawMessage(`{"url":"gcpkms://...","encryptedkey":"BASE64=="}`))
Defensive patterns

Strategy: validation

Validate before calling

func isValidCloudSecretsState(state json.RawMessage) bool {
    var s struct {
        URL          string `json:"url"`
        EncryptedKey []byte `json:"encryptedkey"`
    }
    return json.Unmarshal(state, &s) == nil && strings.Contains(s.URL, "://")
}
// only call NewCloudSecretsManagerFromState when isValidCloudSecretsState(state)

Type guard

func parseCloudState(state json.RawMessage) (*cloudSecretsManagerState, bool) {
    var s cloudSecretsManagerState
    if err := json.Unmarshal(state, &s); err != nil {
        return nil, false
    }
    return &s, true
}

Try / catch

mgr, err := NewCloudSecretsManagerFromState(state)
if err != nil {
    if strings.Contains(err.Error(), "unmarshalling state") {
        return nil, fmt.Errorf("stack secrets state corrupt; restore Pulumi.<stack>.yaml or run 'pulumi stack change-secrets-provider': %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31). Data as JSON: /api/errors/4051eeb2fe85471b. Report an issue: GitHub.