JuliusBrussee/caveman · error
envelope: object kind is required
Error message
envelope: object kind is required
What it means
scopeAAD requires a non-empty Kind because the AAD binds the ciphertext to the type of object being encrypted, preventing ciphertext of one kind from being decrypted as another. The trimmed Kind was empty when SealForScope or OpenForScope was called. The library fails closed to preserve kind separation.
Solutions
- Set Scope.Kind to the object's type string (e.g. "document", "token", "webhook") at every seal/open call site
- Centralize scope construction in one helper that validates Kind before encryption
- Confirm the constant/variable holding Kind is actually initialized (check for shadowed or renamed identifiers)
- Ensure refactors didn't drop the Kind assignment in the struct literal
Example fix
// before
scope := envelope.Scope{OrganizationID: orgID, ProjectID: projID}
// after
scope := envelope.Scope{OrganizationID: orgID, ProjectID: projID, Kind: "document"} Defensive patterns
Strategy: validation
Validate before calling
if strings.TrimSpace(kind) == "" {
return errors.New("object kind required before envelope operations")
} Type guard
func scopeHasKind(s envelope.Scope) bool { return strings.TrimSpace(s.Kind) != "" } Try / catch
_, _, err := /* SealForScope/OpenForScope */
if err != nil && strings.Contains(err.Error(), "object kind is required") {
return ErrMissingObjectKind
} Prevention
- Define Kind constants in one package and use them everywhere
- Wrap envelope calls in a helper that validates the full Scope once
When it happens
Trigger: Calling SealForScope or OpenForScope with envelope.Scope{Kind: ""} or Kind containing only whitespace — e.g. the caller forgot to set Kind or passed a variable that was never initialized.
Common situations: A generic encrypt helper forwards a caller-supplied scope without validating Kind; refactors renamed the Kind constant but a call site still passes an empty string; test fixtures build 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: organization scope is required
- aes-gcm open
- aes-gcm
- arm must be or
- bundle completeness cannot be attested by unsigned export…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/54d3c3df4dfb487d.
Report an issue: GitHub.
Appendix: source
Thrown at shared/platform/envelope/envelope.go:176
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)