Vault

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

ErrorValueDescription
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.

ErrorValueDescription
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

ErrorValueDescription
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

ErrorValueDescription
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

ErrorValueDescription
vault.ErrSecretExists"vault: secret already exists"A secret with this key already exists for this app.

Config errors

ErrorValueDescription
vault.ErrConfigExists"vault: config entry already exists"A config entry with this key already exists for this app.

Rotation errors

ErrorValueDescription
vault.ErrRotationFailed"vault: rotation failed"A secret rotation operation failed.

Authorization errors

ErrorValueDescription
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) {
    // ...
}

On this page