getsops/sops · error

Error marshaling metadata: %s

Error message

Error marshaling metadata: %s

What it means

Emitted by the JSON Store's EmitEncryptedFile when stores.SerializeMetadata fails to convert the tree's sops.Metadata struct into an embeddable tree branch. This indicates the in-memory metadata of the tree could not be serialized (typically a required metadata field conversion failure, not a user data problem).

Source

Thrown at stores/json/store.go:352

// LoadPlainFile loads plaintext json file bytes onto a sops.TreeBranches object
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
	branch, err := store.treeBranchFromJSON(in)
	if err != nil {
		return nil, fmt.Errorf("Could not unmarshal input data: %s", err)
	}
	return sops.TreeBranches{
		branch,
	}, nil
}

// EmitEncryptedFile returns the encrypted bytes of the json file corresponding to a
// sops.Tree runtime object
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
	branches, err := stores.SerializeMetadata(in, stores.MetadataOpts{
		Flatten: stores.MetadataFlattenNone,
	})
	if err != nil {
		return nil, fmt.Errorf("Error marshaling metadata: %s", err)
	}
	return store.EmitPlainFile(branches)
}

// EmitPlainFile returns the plaintext bytes of the json file corresponding to a
// sops.TreeBranches runtime object
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
	out, err := store.jsonFromTreeBranch(in[0])
	if err != nil {
		return nil, fmt.Errorf("Error marshaling to json: %s", err)
	}
	out = append(out, '\n')
	return out, nil
}

// EmitValue returns bytes corresponding to a single encoded value
// in a generic interface{} object
func (store *Store) EmitValue(v interface{}) ([]byte, error) {

View on GitHub (pinned to 13442bb981)

Solutions

  1. Build the tree via LoadEncryptedFile/decryption rather than hand-constructing Metadata, so all fields are populated
  2. Inspect the wrapped error (%s) to identify which metadata field failed to convert
  3. Verify every required Metadata field is set (MAC, KeyGroups, ShamirThreshold, Version, etc.) in custom code
  4. Upgrade/downgrade sops to match the metadata version of the file being processed

Example fix

// before
md := sops.Metadata{} // empty metadata
tree.Metadata = md
out, err := store.EmitEncryptedFile(tree) // "Error marshaling metadata"
// after
tree.Metadata.Version = version // populate all required fields, or:
tree, _ = store.LoadEncryptedFile(originalBytes) // derive metadata from a real file
Defensive patterns

Strategy: try-catch

Validate before calling

func metadataComplete(md sops.Metadata) bool {
	return len(md.KeyGroups) > 0 && md.Version != "" && len(md.MAC) > 0 || md.Version != "" && md.MessageAuthenticationCode != nil
}
// ensure tree.Metadata is populated (from LoadEncryptedFile) before emitting

Try / catch

out, err := store.EmitEncryptedFile(tree)
if err != nil {
	if strings.HasPrefix(err.Error(), "Error marshaling metadata") {
		return fmt.Errorf("tree.Metadata is incomplete/invalid: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling EmitEncryptedFile on a sops.Tree whose Metadata field is incomplete or invalid — e.g. a programmatically built tree missing message authentication, key groups, or having a zero-value Metadata that fails metadataFromInternal/serialization.

Common situations: Custom tooling that constructs a sops.Tree by hand (missing Shards/KeyGroups/LastModified), edits to metadata after decryption, or library version changes where metadata fields were added that a hand-built Metadata struct lacks.

Related errors


AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01). Data as JSON: /api/errors/592e02082f5f1fc5. Report an issue: GitHub.