JuliusBrussee/caveman · error

envelope: tenant scope required for scheme %q

Error message

envelope: tenant scope required for scheme %q

What it means

Open (the scope-unaware entry point) was handed ciphertext whose metadata declares the v2 scoped scheme. Scoped ciphertext requires OpenForScope with the tenant/object Scope so AAD binding is verified; calling plain Open on it would bypass scope authentication, so it is refused.

Source

Thrown at shared/platform/envelope/envelope.go:108

		return nil, nil, fmt.Errorf("envelope: wrap data key: %w", err)
	}
	meta := Metadata{Scheme: scheme, WrappedDataKey: base64.StdEncoding.EncodeToString(wrapped), ScopeHash: scopeHash}
	metaJSON, err = json.Marshal(meta)
	if err != nil {
		return nil, nil, fmt.Errorf("envelope: marshal metadata: %w", err)
	}
	return ciphertext, metaJSON, nil
}

// Open reverses Seal: it unwraps the data key from metadata and decrypts the
// ciphertext. An unknown scheme fails closed.
func Open(ciphertext []byte, metaJSON []byte) ([]byte, error) {
	var meta Metadata
	if err := json.Unmarshal(metaJSON, &meta); err != nil {
		return nil, fmt.Errorf("envelope: parse metadata: %w", err)
	}
	if meta.Scheme == schemeV2 {
		return nil, fmt.Errorf("envelope: tenant scope required for scheme %q", meta.Scheme)
	}
	if meta.Scheme != schemeV1 {
		return nil, fmt.Errorf("envelope: unknown scheme %q", meta.Scheme)
	}
	return open(ciphertext, meta, nil)
}

// OpenForScope opens v2 ciphertext only for its authenticated scope. It also
// reads v1 ciphertext during migration; all new tenant-object writes use v2.
func OpenForScope(ciphertext []byte, metaJSON []byte, scope Scope) ([]byte, error) {
	var meta Metadata
	if err := json.Unmarshal(metaJSON, &meta); err != nil {
		return nil, fmt.Errorf("envelope: parse metadata: %w", err)
	}
	if meta.Scheme == schemeV1 {
		return open(ciphertext, meta, nil)
	}
	if meta.Scheme != schemeV2 {

View on GitHub (pinned to 766dce6b13)

Solutions

  1. Call OpenForScope with the correct tenant/object scope for v2 ciphertext
  2. Use Open only for legacy v1 envelopes during migration
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at shared/platform/envelope/envelope.go:108 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/826cd214b4f00c4c. Report an issue: GitHub.