Secrets error codes
When secret resolution or injection fails, Loom emits a structured error code that classifies the failure. These codes appear in CLI exit output, runtime log events (events.jsonl), and job manifests. Use the error code to jump directly to the cause and fix.
Error code index
| Code | Summary | Severity |
|---|---|---|
SECRETS_PROVIDER_UNAVAILABLE | Provider backend unreachable, misconfigured, or auth failed. | Fatal (required) / Skip (optional) |
SECRETS_REF_INVALID | The ref URI is malformed or uses an unsupported scheme. | Fatal |
SECRETS_REF_NOT_FOUND | Provider is reachable but the referenced entry or field does not exist. | Fatal (required) / Skip (optional) |
SECRETS_REQUIRED_MISSING | A required secret could not be resolved (catch-all after provider attempt). | Fatal |
SECRETS_UNSAFE_DEBUG_TRACE | CI_DEBUG_TRACE=true is set and the job has file: false secrets. | Fatal |
Supported provider schemes
| Scheme | URI format | Auth mechanism |
|---|---|---|
env | env://<VAR_NAME> | Process environment (always available). |
keepass | keepass://<alias>#<entry-path>:<field> | Env-based config: LOOM_KEEPASS_DB_<ALIAS>_PATH, _PASSWORD_ENV, _KEYFILE_ENV. |
op | op://<vault>/<item>/<field> | OP_SERVICE_ACCOUNT_TOKEN env var + op CLI. |
Error details
SECRETS_PROVIDER_UNAVAILABLE
The resolver cannot reach or authenticate with the provider backend.
When it fires:
- The vault/database is unreachable, locked, or auth failed.
- Runtime provider config is missing or invalid.
- No adapter is registered for the ref scheme.
Cause matrix:
| Provider | Likely cause |
|---|---|
keepass | LOOM_KEEPASS_DB_<ALIAS>_PATH is missing or empty. Allowlisted credential env var (_PASSWORD_ENV / _KEYFILE_ENV) points to an unset variable. Database file is unreadable. Decode/unlock failed (wrong password or keyfile). |
env | Should not fire under normal conditions — the process environment is always available. If it does, this indicates an internal resolver bug. |
op | OP_SERVICE_ACCOUNT_TOKEN is missing or empty. The op SDK client failed to initialize. The 1Password service returned an error. |
Fix:
For keepass:
- Verify the alias config env vars are set:
LOOM_KEEPASS_DB_<ALIAS>_PATH— path to the.kdbxfile.LOOM_KEEPASS_DB_<ALIAS>_PASSWORD_ENV— name of the env var holding the password.LOOM_KEEPASS_DB_<ALIAS>_KEYFILE_ENV— name of the env var holding the keyfile path.
- Verify the env vars named by
_PASSWORD_ENV/_KEYFILE_ENVare actually set. - Verify the
.kdbxfile exists and is readable.
The alias is normalized to uppercase with non-alphanumeric characters replaced by _. For example, alias my-db becomes LOOM_KEEPASS_DB_MY_DB_PATH.
For op:
- Verify
OP_SERVICE_ACCOUNT_TOKENis set and non-empty. - Verify network access to 1Password.
Interaction with required:
required: true(default): job fails immediately.required: false: secret is silently omitted; job continues.
SECRETS_REF_INVALID
The ref field cannot be parsed as a valid provider URI.
When it fires:
- Missing or misspelled scheme (e.g.
keepas://instead ofkeepass://). - No scheme at all (e.g.
DATABASE_PASSWORDinstead ofenv://DATABASE_PASSWORD). - Invalid structure for the provider (e.g.
op://missing vault, item, or field segments). - Empty
refvalue. - KeePass ref missing fragment, entry path, or field (e.g.
keepass://mydbwithout#path:field). - KeePass entry path is ambiguous (multiple matches).
Fix:
Verify the ref value matches the expected format for the provider:
| Provider | Valid format | Example |
|---|---|---|
env | env://<VAR_NAME> | env://DATABASE_PASSWORD |
keepass | keepass://<alias>#<entry-path>:<field> | keepass://mydb#Servers/prod-db:Password |
op | op://<vault>/<item>/<field> | op://DevVault/api-key/credential |
Example (invalid):
secrets:
TOKEN:
ref: my-token
Example (valid):
secrets:
TOKEN:
ref: env://MY_TOKEN
SECRETS_REF_NOT_FOUND
The provider is reachable and authenticated, but the specific entry referenced by ref does not exist.
When it fires:
- The environment variable is not set (
env). - The KeePass entry path or field does not exist in the database (
keepass). - The 1Password vault, item, or field does not exist (
op).
Cause matrix:
| Provider | Likely cause |
|---|---|
env | The referenced environment variable is not set in the current shell. |
keepass | The entry path or field name does not match any entry in the .kdbx database. |
op | The vault, item, or field specified in the op:// ref does not exist in 1Password. |
Fix:
- For
env: export the variable before running Loom.
export MY_TOKEN=xxx
loom run --local --workflow .loom/workflow.yml
- For
keepass: open the KeePass database and verify the entry path and field match therefexactly (paths are case-sensitive). - For
op: verify the vault name, item name, and field name in your 1Password account.
Interaction with required:
required: true(default): job fails immediately.required: false: secret is silently omitted; job continues.
SECRETS_REQUIRED_MISSING
Catch-all for any required secret that fails resolution after the provider attempt, when no more specific error code applies.
When it fires:
The provider returned an ambiguous failure that does not map to SECRETS_PROVIDER_UNAVAILABLE, SECRETS_REF_INVALID, or SECRETS_REF_NOT_FOUND.
Fix:
- Check the job's
secretsblock for the failing secret name. - Verify the
refURI is correct and the provider is accessible. - Check the
events.jsonlfor the failing job — the error event includesProviderandNamefields for correlation. - If the secret is not critical, set
required: falseto allow the job to proceed without it.
SECRETS_UNSAFE_DEBUG_TRACE
Debug trace and direct-env secrets cannot coexist safely.
When it fires:
Both conditions are true:
CI_DEBUG_TRACE=trueis set (via variables or environment).- The job has one or more secrets with
file: false.
Debug trace enables shell tracing (set -x), which prints every command and its arguments to stderr. Secrets injected as direct environment values (file: false) would be exposed in the trace output. Loom's redaction engine masks secret values in structured log output, but shell-level trace output is emitted before Loom can intercept it.
Fix:
| Option | Action |
|---|---|
| A | Remove CI_DEBUG_TRACE=true from the job's variables. |
| B | Change secrets to file: true (the default). File-path injection is safe under debug trace — the trace reveals only the file path, not the secret value. |
| C | Remove the secrets from the job if they are not needed. |
If all secrets in a job use file: true (the default), debug trace is allowed.
Diagnostic metadata in error events
When a secrets error occurs, the runtime event in events.jsonl includes diagnostic metadata — never the secret value itself:
| Field | Description |
|---|---|
Code | The error code (e.g. SECRETS_REF_NOT_FOUND). |
Provider | Which provider scheme was attempted (e.g. env, keepass, op). |
Name | The secret variable name from the secrets block (e.g. DATABASE_PASSWORD). |
RefFingerprint | A hash of the ref URI for correlation without exposing vault structure (optional, Alpha). |
Message | Human-readable error description. |
The stable public contract for SecretsError and these codes is the loom-check/contracts package. The type is designed to be audit-safe: implementations must not include secret bytes and should avoid embedding full ref strings.
Related pages
- Secrets concept — mental model, injection modes, redaction
- Secrets workflow authoring — YAML syntax, provider URIs, examples
- Runtime logs contract — pointer-first log navigation
- Receipts contract — receipt pointers for triage