JuliusBrussee/caveman · error
envelope: organization scope is required
Error message
envelope: organization scope is required
What it means
scopeAAD refuses to build the additional authenticated data because the Scope has an empty OrganizationID after trimming whitespace. Envelope encryption binds ciphertext to a tenant scope, so sealing or opening without an organization would produce or accept data with no tenant binding. The library fails closed instead.
Solutions
- Populate Scope.OrganizationID with the authenticated tenant's ID before calling SealForScope/OpenForScope
- Trim/validate org context upstream (middleware) and reject requests lacking it before reaching the envelope layer
- Check struct-literal field ordering — Go unkeyed literals bind positionally; use keyed fields
- Fix test fixtures to use a real, non-empty organization ID
Example fix
// before
scope := envelope.Scope{"", projectID, "document"}
// after
if strings.TrimSpace(orgID) == "" { return errors.New("org required") }
scope := envelope.Scope{OrganizationID: orgID, ProjectID: projectID, Kind: "document"} Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(orgID) == "" {
return errors.New("organization id required before envelope operations")
} Type guard
func scopeHasOrg(s envelope.Scope) bool { return strings.TrimSpace(s.OrganizationID) != "" } Try / catch
aad, id, err := /* via SealForScope/OpenForScope */
if err != nil && strings.Contains(err.Error(), "organization scope is required") {
return ErrMissingTenantContext
} Prevention
- Populate tenant context in middleware before any crypto call
- Always build Scope with keyed struct fields
- Reject requests missing org context at the handler boundary
When it happens
Trigger: Calling SealForScope or OpenForScope with envelope.Scope{OrganizationID: ""} or one containing only whitespace (e.g. from an unset request header or empty tenant context).
Common situations: A request missing tenant context reaches the crypto layer; auth middleware did not populate the org ID; a struct literal was built with fields in the wrong order; tests pass a zero-value Scope.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- envelope: object kind is required
- tenantkey: safe organization and project scope are required
- aes-gcm open
- aes-gcm
- arm must be or
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/b8d28f06957c7cf3.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/envelope/envelope.go:173
}
ns := gcm.NonceSize()
if len(ciphertext) < ns {
return nil, fmt.Errorf("envelope: ciphertext too short")
}
nonce, ct := ciphertext[:ns], ciphertext[ns:]
plaintext, err := gcm.Open(nil, nonce, ct, aad)
if err != nil {
return nil, fmt.Errorf("envelope: open: %w", err)
}
return plaintext, nil
}
func scopeAAD(scope Scope) ([]byte, string, error) {
scope.OrganizationID = strings.TrimSpace(scope.OrganizationID)
scope.ProjectID = strings.TrimSpace(scope.ProjectID)
scope.Kind = strings.TrimSpace(scope.Kind)
if scope.OrganizationID == "" {
return nil, "", fmt.Errorf("envelope: organization scope is required")
}
if scope.Kind == "" {
return nil, "", fmt.Errorf("envelope: object kind is required")
}
aad, err := json.Marshal(struct {
Version int `json:"version"`
OrganizationID string `json:"organization_id"`
ProjectID string `json:"project_id"`
Kind string `json:"kind"`
}{2, scope.OrganizationID, scope.ProjectID, scope.Kind})
if err != nil {
return nil, "", fmt.Errorf("envelope: encode scope: %w", err)
}
sum := sha256.Sum256(aad)
return aad, hex.EncodeToString(sum[:]), nil
}
View on GitHub (pinned to 3ee70a1026)