Error Handling
Sentinel errors for all Vault operations.
Vault defines sentinel errors in the root vault package. Use errors.Is to check for specific error conditions in your application code.
Using errors.Is
import (
"errors"
"github.com/xraph/vault"
)
sec, err := secretSvc.Get(ctx, "my-key", "myapp")
if errors.Is(err, vault.ErrSecretNotFound) {
// secret does not exist for this app
}All Vault services return these sentinel errors. Store backends wrap them appropriately so that errors.Is works regardless of which backend is in use.
Sentinel errors by category
Store errors
| Error | Value | Description |
|---|---|---|
vault.ErrNoStore | "vault: no store configured" | No store backend has been configured. |
Not-found errors
These are returned when a requested entity does not exist for the given key and app ID.
| Error | Value | Description |
|---|---|---|
vault.ErrKeyNotFound | "vault: key not found" | Generic key not found (used by source package). |
vault.ErrSecretNotFound | "vault: secret not found" | No secret with the given key exists for this app. |
vault.ErrFlagNotFound | "vault: flag not found" | No flag definition with the given key exists for this app. |
vault.ErrConfigNotFound | "vault: config entry not found" | No config entry with the given key exists for this app. |
vault.ErrOverrideNotFound | "vault: override not found" | No tenant override exists for the given key, app, and tenant. |
vault.ErrRotationNotFound | "vault: rotation policy not found" | No rotation policy exists for the given secret key and app. |
vault.ErrAuditNotFound | "vault: audit entry not found" | No audit entry with the given ID exists. |
vault.ErrRunNotFound | "vault: workflow run not found" | No workflow run with the given ID exists. |
vault.ErrDLQNotFound | "vault: DLQ entry not found" | No dead-letter queue entry with the given ID exists. |
vault.ErrCronNotFound | "vault: cron entry not found" | No cron entry with the given ID exists. |
vault.ErrEventNotFound | "vault: event not found" | No event with the given ID exists. |
vault.ErrWorkflowNotFound | "vault: workflow not found" | No workflow with the given ID exists. |
Cryptography errors
| Error | Value | Description |
|---|---|---|
vault.ErrDecryptionFailed | "vault: decryption failed" | Decryption of a secret value failed (wrong key or corrupted ciphertext). |
vault.ErrEncryptionFailed | "vault: encryption failed" | Encryption of a secret value failed. |
vault.ErrInvalidKey | "vault: invalid encryption key" | The provided encryption key is invalid (e.g. wrong length). |
The crypto package also defines its own error:
crypto.ErrInvalidKeySize // "crypto: key must be exactly 32 bytes for AES-256"Feature flag errors
| Error | Value | Description |
|---|---|---|
vault.ErrFlagDisabled | "vault: flag is disabled" | The flag definition has Enabled: false. |
vault.ErrFlagExists | "vault: flag already exists" | A flag with this key already exists for this app. |
vault.ErrInvalidFlagKey | "vault: invalid flag key" | The flag key is empty or malformed. |
Secret errors
| Error | Value | Description |
|---|---|---|
vault.ErrSecretExists | "vault: secret already exists" | A secret with this key already exists for this app. |
Config errors
| Error | Value | Description |
|---|---|---|
vault.ErrConfigExists | "vault: config entry already exists" | A config entry with this key already exists for this app. |
Rotation errors
| Error | Value | Description |
|---|---|---|
vault.ErrRotationFailed | "vault: rotation failed" | A secret rotation operation failed. |
Authorization errors
| Error | Value | Description |
|---|---|---|
vault.ErrUnauthorized | "vault: unauthorized" | The caller is not authorized to perform this operation. |
Source package errors
The source package defines its own not-found error:
source.ErrKeyNotFound // "source: key not found"This is returned when no source in a chain contains the requested key. The source.Database adapter converts vault.ErrConfigNotFound to source.ErrKeyNotFound automatically.
Error handling patterns
Check for specific errors
sec, err := secretSvc.Get(ctx, "api-key", "myapp")
switch {
case errors.Is(err, vault.ErrSecretNotFound):
// key does not exist -- create it
case err != nil:
// unexpected error
default:
// success
}Flag evaluation with defaults
The type-safe flag.Service methods (Bool, String, Int, Float) return the default value on any error, including ErrFlagNotFound. This is intentional -- flag evaluation should never crash your application.
// Returns false (the default) if the flag does not exist, is disabled,
// or evaluation encounters any error.
enabled := flagSvc.Bool(ctx, "new-dashboard", false)If you need to distinguish between "flag not found" and "flag exists but evaluates to default", use the Engine.Evaluate method directly:
val, err := engine.Evaluate(ctx, "new-dashboard", "myapp")
if errors.Is(err, vault.ErrFlagNotFound) {
// flag definition does not exist
}Config with fallback
Similarly, config.Service type-safe accessors return the default value on error:
// Returns 50 if "rate-limit" is not found or has a type mismatch.
limit := configSvc.Int(ctx, "rate-limit", 50)Override resolution
The override.Resolver silently falls through when ErrOverrideNotFound is returned -- it returns the app-level config value instead. Only unexpected errors are propagated.
val, err := resolver.Resolve(ctx, "rate-limit", "myapp")
if errors.Is(err, vault.ErrConfigNotFound) {
// neither override nor app config exists
}Wrapped errors
Service methods may wrap sentinel errors with additional context using fmt.Errorf and %w. Always use errors.Is rather than string comparison:
// Works correctly even if the error is wrapped.
if errors.Is(err, vault.ErrSecretNotFound) {
// ...
}