# Handling Missing Secrets
Control what happens when a secret can't be resolved using the `if_missing` setting. This is especially useful for CI environments or when some secrets are optional.
## Available Modes
- **`error`** - Fail the command if a secret cannot be resolved (strictest)
- **`warn`** - Print a warning and continue (default)
- **`ignore`** - Silently skip missing secrets
## Priority Chain
You can set `if_missing` at multiple levels. fnox uses the first match:
1. **CLI flag** (highest priority): `--if-missing error`
2. **Environment variable**: `FNOX_IF_MISSING=warn`
3. **Secret-level config**: `[secrets.MY_SECRET]` with `if_missing = "error"`
4. **Top-level config**: Global default for all secrets
5. **Base default environment variable**: `FNOX_IF_MISSING_DEFAULT=error`
6. **Default**: `warn` (lowest priority)
## Per-Secret Configuration
Set different behaviors for different secrets:
```toml
[secrets]
# Critical secrets must exist
DATABASE_URL = { provider = "aws", value = "database-url", if_missing = "error" } # Fail if missing
# Optional secrets
ANALYTICS_KEY = { provider = "aws", value = "analytics-key", if_missing = "ignore" } # Continue silently if missing
# Warn about missing secrets (default)
CACHE_URL = { provider = "aws", value = "cache-url", if_missing = "warn" } # Print warning if missing
```
## Top-Level Default
Set a default for all secrets:
```toml
# Make all secrets strict by default
if_missing = "error"
[secrets]
DATABASE_URL = { provider = "age", value = "encrypted..." } # Inherits if_missing = "error"
API_KEY = { provider = "age", value = "encrypted..." } # Inherits if_missing = "error"
OPTIONAL_FEATURE_FLAG = { default = "false", if_missing = "ignore" } # Override - this one can be missing
```
## Runtime Override with CLI
Override config settings at runtime:
```bash
# Override to be lenient (useful in CI with missing secrets)
fnox exec --if-missing ignore -- npm test
# Override to be strict (ensure all secrets are present)
fnox exec --if-missing error -- ./deploy.sh
# Use warnings (default)
fnox exec --if-missing warn -- npm start
```
## Runtime Override with Environment Variable
```bash
# Set globally for a session
export FNOX_IF_MISSING=warn
fnox exec -- npm start
# Or inline
FNOX_IF_MISSING=error fnox exec -- ./critical-task.sh
```
## Base Default Behavior
Set a default behavior when `if_missing` is not configured anywhere:
```bash
# Change the default from "warn" to "error"
export FNOX_IF_MISSING_DEFAULT=error
# Now all secrets without explicit if_missing will fail if missing
fnox exec -- ./my-app
```
This is useful for:
- Making your entire project strict by default
- CI/CD environments where you want failures by default
- Development environments where you want warnings by default
**Priority:** This has the lowest priority and only applies when `if_missing` is not set in:
- CLI flags
- `FNOX_IF_MISSING` env var
- Secret-level config
- Top-level config
## CI/CD Examples
### Forked PRs (Secrets Unavailable)
```yaml
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests (some secrets may be missing in forks)
env:
FNOX_IF_MISSING: ignore # Don't fail on missing secrets
run: |
fnox exec -- npm test
```
### Production Deployment (Strict)
```yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Deploy to production
env:
FNOX_IF_MISSING: error # Fail if any secret is missing
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
fnox exec --profile production -- ./deploy.sh
```
### Staging (Warn on Missing)
```yaml
# .github/workflows/staging.yml
jobs:
deploy-staging:
runs-on: ubuntu-latest
steps:
- name: Deploy to staging
env:
FNOX_IF_MISSING: warn # Print warnings but continue
run: |
fnox exec --profile staging -- ./deploy.sh
```
## Use Cases
### Optional Analytics/Monitoring
```toml
[secrets]
# Won't break the app if missing
SENTRY_DSN = { provider = "aws", value = "sentry-dsn", if_missing = "ignore" }
DATADOG_API_KEY = { provider = "aws", value = "datadog-key", if_missing = "ignore" }
```
### Required Database
```toml
[secrets]
DATABASE_URL = { provider = "aws", value = "database-url", if_missing = "error" } # Must exist or fail
```
### Development Defaults
```toml
[secrets]
REDIS_URL = { default = "redis://localhost:6379", if_missing = "warn" } # Warn if missing, but provide a default
```
## Behavior Summary
| `error` | Fail command | Required secrets (database, API keys) |
| `warn` | Print warning, continue | Optional but recommended secrets |
| `ignore` | Silent skip | Truly optional features (analytics, etc.) |
## Next Steps
- [Profiles](/guide/profiles) - Different secrets per environment
- [Import/Export](/guide/import-export) - Migrate secrets between systems
- [Real-World Example](/guide/real-world-example) - Complete setup with error handling