Troubleshooting
The exact messages the varsafe CLI prints, what causes each one, and the fastest fix: sign-in, keychain, permissions, context, running commands, composed secrets, installs and exit codes.
Search this page for the line in your terminal: the CLI’s messages are stable, and each one heads its own section below. The two dashboard sign-in messages under Signing in to the dashboard are quoted the same way.
Find your symptom
No exact message to search for? Start from what you see:
- My app does not see a variable
- Works locally, fails in CI
- Permission denied, or another refusal
- Wrong project or environment
- Importing a .env file stops, or skips keys
- An AI agent cannot connect, or is refused (MCP guide)
- SSO sign-in fails (SSO guide)
- The installer or the binary fails
- My app still has the old value after a rotation
- A script needs to know what an exit code means
Start here: what is the CLI using?
Most problems come down to one of two questions: which credential is this machine using, and which project and environment will the next command act on. One command answers both:
varsafe statusvarsafe status shows the credential, the saved context, and what that context contains. For the credential alone, and what it is allowed to do:
varsafe whoamiRun varsafe whoami first on any permission error. It names the account or token in use and its scopes, which settles most “it works on my machine” questions in one line.
Signing in
Not signed in
✖ Not signed in
Run `varsafe login` to authenticate, or set VARSAFE_TOKEN env var for CI/CD
There is no stored credential and no token in the environment. On your own machine, run varsafe login. On a server or CI runner, export VARSAFE_API_TOKEN (the CLI also accepts VARSAFE_TOKEN); every command picks it up with no login step. See CI/CD pipelines.
Session expired
✖ Session expired
Run `varsafe login` to re-authenticate
The API rejected the varsafe login session stored on this machine. It was revoked, for example from Profile → CLI Sessions in the dashboard, or it expired. Run varsafe login again. The CLI also clears the stored credential and saved context, so the next command starts clean.
The API token in VARSAFE_API_TOKEN was rejected
✖ The API token in VARSAFE_API_TOKEN was rejected
It is expired, revoked or wrong. Check VARSAFE_API_TOKEN, or replace it with a new token from the dashboard's API tokens page
The CLI was using a token from the environment and the API refused it. The message names the variable the token came from: VARSAFE_API_TOKEN, or VARSAFE_TOKEN when only that one is set. The token was revoked, rotated (rotation retires the old value), reached its expiry date, or was copied incompletely. Logging in will not fix this: create or rotate a token on the dashboard’s API tokens page and update the variable or CI secret that holds it.
A pipeline that ran for weeks and now fails on every job with this message has usually reached its token’s expiry date. Every token expires: after 90 days at most on the Developer plan, and one year on Team. Rotating does not extend the date, so create a new token and put a reminder for its expiry in your rotation schedule. See API tokens and API token management.
Invalid or expired token
Printed by varsafe login --token when the token you entered is not accepted. Usually it was copied incompletely, revoked, rotated, or has expired. Nothing is stored when this happens. Copy a fresh token from the API tokens page and enter it at the masked prompt:
varsafe login --token-prompt
If VARSAFE_API_TOKEN is set in your shell and nothing is stored yet, varsafe login reports Already authenticated via VARSAFE_API_TOKEN and does nothing. To sign in as yourself anyway, run varsafe login --force. From then on your stored login is used, and the variable is ignored; see the next section.
My token is set but the CLI uses my login
A varsafe login stored on this machine comes first. The CLI uses VARSAFE_API_TOKEN only when nothing is stored, so exporting a token in a shell where you are signed in does not change who the commands run as. Check which credential is in use:
varsafe status
The Credential line reads API token from VARSAFE_API_TOKEN when the variable is in use, and CLI credential when your stored login is. To run as the token, run varsafe logout first, or run the command where nothing is stored: a CI runner, a container, or another user account.
A stored login that has expired does not hand over to the token. The command fails instead, so you never act as a different identity without knowing it:
✖ Your credential expired. Run `varsafe login` to sign in again.
A credential is stored on this machine but could not be read
✖ A credential is stored on this machine but could not be read, and an API token is set in the environment. Refusing to silently run as a different identity.
Run `varsafe logout` to remove the unreadable credential, then re-run with the API token.
A login is stored, but the CLI cannot read it (usually because the OS keychain entry was removed or cannot be reached), and VARSAFE_API_TOKEN is set. The CLI will not quietly switch to the token: the token may belong to a service account with different access, and everything you do would be recorded under its name. At a terminal, it offers the switch instead and asks you to type use <token name>. In a script or CI job it stops with this message. If you mean to run as the token, run varsafe logout, then the command again.
Works locally, fails in CI
On your machine the CLI usually runs as your varsafe login, with your role in every team you belong to. In CI it runs as the token in VARSAFE_API_TOKEN, which reaches one team and only the projects and environments chosen when it was created. Run the failing command with the CI token on your machine to see the difference, and check these in order:
- Which project and environment. A runner has no saved context and no prompt, so the CLI stops with
Project is required. Pass-i(or-p) and-eon every command. - What the token reaches.
varsafe whoamilists the token’s team, projects, environments and access. A token outside the project’s team is refused withActive team does not match API token scope; see Permissions. - Whether it can write. A read-only token cannot set or unset secrets, and changing a protected environment needs a token scoped to that environment.
- Whether it is still valid. A token that expired, was revoked or was rotated fails with
The API token in VARSAFE_API_TOKEN was rejected.
See CI/CD pipelines for a working setup.
Signing in on a server, over SSH, or without a browser
varsafe login does not need a browser on the machine it runs on. It prints a short code and a URL; open the URL on any device where you are signed in to varsafe, check the code matches, and approve. If no browser opens, the CLI says so and prints the URL to open:
⚠ Could not open a browser — open this URL to approve:
The code is valid for 10 minutes. These messages mean the approval did not happen in time, or was refused:
✖ The code expired before it was approved. Run `varsafe login` again.
✖ Timed out waiting for approval. Run `varsafe login` again.
✖ The request was denied in the browser.
Run varsafe login again and approve within the window.
On a machine with no OS keychain (a fresh server, a container, a spare machine), varsafe login still works when you run it at a terminal. The approval page tells you the machine cannot store your identity securely and offers a machine token instead: limited to one team and the projects and environments you choose, and expiring. Approve it and the CLI signs in with that token.
CI runners are different: nobody is there to approve. Do not run varsafe login in a pipeline. Export VARSAFE_API_TOKEN instead; see CI/CD pipelines.
Signing in to the dashboard
There is already a varsafe account with this email
There is already a varsafe account with this email. Sign in the way you did before, then connect this provider from Connected accounts on your profile.
You signed in with GitHub, GitLab, Google or Bitbucket, and that provider’s email already belongs to a varsafe account created another way. varsafe never attaches a provider to an existing account on its own: whoever controlled that provider account would get a way into yours. Sign in as you did before (password, passkey or the provider you used first), open Profile → Connected accounts and click Connect next to the provider. From then on it signs you in. See Connected Accounts.
This account is in passkey-only mode
This account is in passkey-only mode. Sign in with one of its passkeys.
The account’s owner turned on passkey-only mode, so a password, provider or SSO sign-in is refused. Use Sign in with passkey. If none of the account’s passkeys is available any more, contact support.
The OS keychain
OS secure storage (keychain) is unavailable
✖ OS secure storage (keychain) is unavailable
Server or CI: set VARSAFE_API_TOKEN — no keychain and no `varsafe login` needed.
Desktop: start a D-Bus Secret Service (gnome-keyring or KWallet), then retry.
Signed in on this machine before? Run `varsafe logout` to remove the stored credential.
The CLI keeps your credential encrypted, with the key held by the operating system’s keychain, so a copy of its files alone recovers nothing. This message means it could not reach a keychain. The desktop line names your own OS’s fix (Keychain Access on macOS, Credential Manager on Windows).
The built-in diagnostic tells you which part is broken:
varsafe doctorIt checks two things separately: that the CLI’s keychain component loads, and that a real write-and-read through the OS keychain succeeds. Add --json for machine-readable output.
On hardened servers and some CI images the cause is a temporary directory mounted noexec. The CLI unpacks its keychain component into $TMPDIR and loads it from there, so a non-executable temp directory breaks it even when the keychain itself is fine. The CLI detects this and retries from ~/.cache/varsafe/run (under $XDG_CACHE_HOME when that is set), so it normally fixes itself. When that directory is not usable either, it says so:
varsafe: temp dir "/tmp" is mounted noexec and no exec-able fallback was found, so the OS keychain addon can't load.
Create a directory you own that allows execution, and point TMPDIR at it:
mkdir -p "$HOME/.cache/varsafe/run"
TMPDIR="$HOME/.cache/varsafe/run" varsafe doctor --addon-only
If your home directory is mounted noexec too, use any other directory you own that allows execution.
The OS keychain is locked or not responding
⚠ Waiting for the OS keychain — if it is locked, unlock it to continue (a password prompt may be open).
✖ The OS keychain is locked or not responding.
The keychain is there, but locked. Its unlock prompt was dismissed, never appeared, or is still waiting behind another window. varsafe waits up to 30 seconds, long enough to type your password, then stops rather than hang. Unlock the keychain and run the command again:
- Linux (GNOME): answer the unlock prompt, or unlock the Login keyring in Passwords and Keys. On KDE, open the wallet in KWalletManager.
- macOS: unlock the login keychain in Keychain Access.
A keychain is normally unlocked by the password you type when you log in to your computer, so this tends to follow a login that skipped it: automatic login, a fingerprint, or a session restored after a crash. varsafe doctor reports it on its own line ("roundtrip": "locked" with --json).
Your stored credential is fine. Do not run varsafe logout or varsafe login to fix this. A login started while the keychain is locked stops with the same message rather than storing your credential somewhere less safe.
Permissions
Permission denied and other refusals
When the API refuses a request, the CLI prints the API’s own reason. Run varsafe whoami to see what the credential may do, then find the message below.
A varsafe login session never does more than your team role allows: a Viewer stays read-only whatever was approved. An API token’s access is fixed when it is created, on the dashboard’s API tokens page. See Roles and permissions and API tokens.
This CLI sign-in was not approved for …
Your varsafe login was approved without that permission. The default, Standard, can read secrets but not change them.
Fix: varsafe login --force, and choose Full access to create, update or delete secrets. For a token in VARSAFE_API_TOKEN, replace it with one that has the access.
CLI credential lacks required scope: …
Your role in that team does not allow it, whatever the sign-in was approved for. A Viewer, for example, cannot change secrets.
Fix: ask a team owner or admin for a role that allows it.
This CLI credential was not granted access to the active team
The project you named belongs to a team this sign-in was not approved for.
Fix: varsafe login --force, and include that team when you approve.
This CLI credential no longer grants access to any team
You were removed from, or deactivated in, every team the sign-in covered.
Fix: ask a team owner or admin to restore your membership.
Active team does not match API token scope
The token belongs to a different team than the project you named.
Fix: use a token created in that project’s team.
This token can change a protected environment only when it is scoped to that environment …
A write token for all environments tried to change a protected one, such as production.
Fix: create a write token with that environment chosen under Scope. See protected environments.
This endpoint is not available to CLI credentials
The action is dashboard-only.
Fix: do it in the dashboard.
… is a protected environment
✖ Production is a protected environment
Re-run with --yes to remove DATABASE_URL without confirmation
varsafe set and varsafe unset ask you to type the environment’s slug (for example production) before changing a protected environment. A script or CI job cannot answer a prompt, so it stops here instead. If the change is intended, pass --yes.
Project and environment context
varsafe list shows nothing, or the wrong secrets
You are looking at a different project or environment than you think. The CLI resolves context in this order: command flags (-p/-i/-e), then a .varsafe file in the repository, then the machine’s saved context. Check, then fix:
# What will the next command act on?
varsafe status
# Choose again
varsafe use -p my-api -e development
# Or skip saved context for one command
varsafe list -p my-api -e development
Inside a git repository, varsafe use saves its choice to a .varsafe file at the repository root, which wins over the machine-wide context. varsafe use --clear clears the machine-wide context only; delete .varsafe yourself to reset a repository.
Project not found. It may have been deleted.
✖ Project not found. It may have been deleted. Run `varsafe use` to update.
Your saved context names a project (or environment) that no longer exists, or that this credential cannot see. Run varsafe use to pick again. If the project should exist, varsafe whoami shows whether you are signed in as the account or token you expect.
Project is required in scripts and CI
✖ Project is required. Use -p <project> or -i <project-id> to specify.
In a non-interactive session (CI, cron, piped output) the CLI cannot ask which project you mean, so it must come from a flag or a saved context. In automation, pass -i with the project ID: unlike the name, it survives a rename. See CI/CD pipelines.
Composed secrets
My app received the literal text ${DB_PASS}
The secret is an ordinary value that happens to contain ${DB_PASS}, not a composed secret. varsafe never expands ${...} in an ordinary value; see Values are stored, not interpreted.
Check which it is:
varsafe list --revealThe Kind column reads composed or literal. To make it a composition, set it again with --template:
varsafe set DATABASE_URL --template 'postgres://${DB_PASS}@db.internal/app'If the secret already reads composed and your process still got ${...}, something in your pipeline is asking for the source form. Look for a stray --source on the read.
This value is built from other secrets and cannot be resolved
The composition names a key that does not exist in this environment, or its references loop back on themselves. Compositions resolve within one environment, so this usually means one was written to an environment that does not have its inputs yet. Create the missing key first, or check you are pointed at the environment you meant:
varsafe status
varsafe list
This secret is composed from other secrets
✖ This secret is composed from other secrets. Update to a version that supports composition, or edit it in the dashboard
You tried to overwrite a composed secret with a plain value, with varsafe set, a rotation, or an import. varsafe refuses, because the overwrite would quietly freeze the secret at its current value and stop it following future rotations. You have three choices:
- Change what it is built from: set it again with
--template. - Make it a plain value on purpose: open it in the dashboard, choose Edit, then Convert to plain value.
- Rotate the value inside it: rotate the secret it references, not the composition. See Rotating.
If you are on an old CLI, varsafe update brings composition support.
Other secrets are composed from this one
✖ Other secrets are composed from this one. Choose whether to keep them working or delete them too
You are deleting a secret that other secrets are built from, and varsafe will not guess what should happen to them. Say which:
varsafe unset DB_PASS --cascade # delete the dependents too
varsafe unset DB_PASS --flatten # keep them working by copying this value into each
If you are deleting the secret because it leaked, use --cascade. --flatten would copy the compromised value into every dependent, where it becomes an ordinary value nobody will think to rotate. See Composed secrets.
Running commands with secrets
My app does not see a variable
varsafe run prints where it read from on stderr before starting your command:
Injecting 5 secrets from my-api/development
No secrets to inject from my-api/staging
Check, in order:
- The project and environment. If the name after
fromis not the one you meant, fix the context (see Project and environment context) or pass-pand-e.No secrets to injectmeans that environment is empty, or your--includematched nothing in it. - The key exists there.
varsafe listwith the same-pand-eshows the names in that environment. - The filters.
--includeinjects only the keys matching its patterns, and--prefixrenames every injected key (--prefix monitoringturnsAPI_KEYintoMONITORING_API_KEY). - Your shell.
$VAR,&&,|and redirects on the command line are handled by your shell before varsafe runs; see the next section. - When it started. A process keeps the environment it started with; see the rotation section.
varsafe run -- echo $DATABASE_URL prints an empty line
Your shell expands $DATABASE_URL before varsafe starts, while the variable is still unset, so echo receives an empty argument. The secret was injected; the check was wrong. Have a shell inside the command read it instead, and print only whether it is set, not its value:
varsafe run -- sh -c 'echo "${DATABASE_URL:+set}"'
The same applies to &&, | and redirects. In varsafe run -- npm run migrate && npm start, only the migration gets the secrets: your shell runs npm start afterwards, outside varsafe. varsafe run passes the command to your program as it is, without a shell, so wrap shell syntax in sh -c '...' or use --shell, which takes one command string:
varsafe run --shell 'npm run migrate && npm start'
Refusing to inject …
✖ Refusing to inject NODE_OPTIONS: it controls how the command loads code, so a secret could run arbitrary code in this process. Remove it from the environment, or set it in your shell instead.
varsafe run refuses secrets whose names control how a program loads code: PATH, NODE_OPTIONS, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES, DYLD_LIBRARY_PATH, PYTHONPATH, PYTHONSTARTUP, PERL5OPT, RUBYOPT, BASH_ENV and GIT_SSH_COMMAND. Anyone able to change one such secret could otherwise run code on every machine and CI job that reads the environment. Nothing runs and the command exits with code 5.
These are configuration, not secrets. Delete the secret, or leave it out with --include, and set the variable in your shell or CI job around varsafe run, where whoever runs the command can see it.
Failed to run command: exit code 127 or 126
varsafe run exits with your command’s own exit code. When the command could not start at all, it prints Failed to run command: with the system’s reason, and exits the way a shell would:
| Exit code | Meaning | Common causes |
|---|---|---|
127 |
The command was not found | A typo, a program not on PATH, or a local script run without ./ |
126 |
The command was found but cannot be executed | A script without the execute bit (chmod +x), or a file that is not a program |
Because there is no shell, shell builtins such as source and your own aliases are not available either. Run them with --shell or sh -c '...'.
My app still sees the old value after a rotation
A process reads its environment once, when it starts. Changing or rotating a secret does not reach a process that is already running, including one started by varsafe run. Restart or redeploy it to pick up the new value. CI jobs fetch current values on every run, so they need nothing. See Handling running applications.
Importing a .env file
error: unknown command 'import'
error: unknown command 'import'
(Did you mean export?)
varsafe import arrived in CLI 7.8.0, and this CLI is older: varsafe --version says which you have. Run varsafe update, then the command again.
Can't import .env: …
✖ Can't import .env: line 7 cannot be read as KEY=value; API_KEY is set more than once (lines 2 and 9). Fix the file, then import again
varsafe import checks the whole file before it writes anything, and refuses it when the file is ambiguous. A key set twice is refused because a .env loader keeps only the last value, and the import will not guess which one you meant. A line that is not KEY=value (an unquoted value spread over several lines, a stray paste) is named by number only, because it may itself hold a secret. Fix those lines and run the command again; nothing was written.
The same message says when the file is a varsafe-encrypted export, whose values are ciphertext (use it with varsafe run --env-file instead), or not UTF-8 text, which is what PowerShell’s > writes. Save it as UTF-8, or create it with Out-File -Encoding utf8.
A key shows as skip or kept
skip means varsafe cannot store that key or value: a key must start with an uppercase letter and contain only A–Z, 0–9 and _, and a value can be up to 64 KB. Rename the key in your file and in the code that reads it. kept means the environment already has that key, so the import left it as it is; add --replace-existing to overwrite it with the file’s value.
The import stopped: …
A request failed partway, and the import stopped there. Keys listed as refused were not written: the API turned the request down, for example because a secret changed after the plan was made, or because your sign-in may not change secrets (the error after the list says which). Keys listed as not confirmed may or may not have been written, usually after a network failure. Check with varsafe list, then run the same command again: it shows a fresh plan before writing.
Encrypted .env files
--env-file refuses the file
✖ Cannot open .env: a value in it was changed, moved to another name, or encrypted with another key. Re-export it with `varsafe export -o .env`.
A value in the file no longer matches what was exported: it was edited, copied onto another variable, or pasted in from a file encrypted to a different environment. varsafe refuses the whole file rather than inject part of it. Export it again from the environment it belongs to.
✖ Cannot open .env: it is encrypted with key ek_…, which this environment does not have — the key was deleted, or the file comes from another environment. Re-export it with `varsafe export -o .env`.
The run resolved a different environment from the one the file was exported from, or that environment’s keys were deleted, after which no file encrypted to them can be opened. Pass the right one with -e (and -p), or export again.
✖ .env.local is not encrypted. --env-file only reads encrypted files (see `varsafe export`). To merge a plaintext file, source it in your shell instead: set -a; . ./.env.local; set +a
--env-file reads only files written by varsafe export, so a plaintext file can never stand in for an encrypted one. Source a plaintext file inside the command, as the CLI reference shows.
Opening a file needs the same access as varsafe run. A login approved as Read only is refused with This CLI sign-in was not approved for …, and varsafe login --force with Standard access fixes it. If your role itself does not allow reading values, the message is CLI credential lacks required scope: … instead. See Permissions. See Encrypted .env files.
Installing
Installer refuses your platform
Unsupported architecture: <arch>
The installer supports Linux and macOS on x64 (x86_64/amd64) and arm64 (arm64/aarch64), and picks a musl build when it finds a musl system such as Alpine. Anything else (32-bit ARM on older Raspberry Pi OS, i686, s390x, RISC-V) has no published build and stops here.
Linux arm64 is supported, on both glibc and musl. If you are on Graviton, a modern Raspberry Pi, or an ARM CI runner and see this, re-fetch install.sh: installers from before the arm64 builds refuse the platform outright. The installer prints the build it chose, for example Detected platform: linux-arm64-musl, which is the quickest way to confirm it identified your machine.
The downloaded binary did not run on this system:
It was killed by signal 4. Possible cause: this CPU lacks the x86-64-v2 instructions varsafe's x64 build needs (SSSE3, SSE4.1, SSE4.2, POPCNT).
On x64, varsafe needs those instructions, which every Intel and AMD processor from about 2010 onwards has. A virtual machine on the bare qemu64 or kvm64 CPU model hides them: set its CPU type to x86-64-v2 or newer, or to host, and re-run the installer.
Alpine or musl: “Error loading shared library libstdc++.so.6”
Error loading shared library libstdc++.so.6: No such file or directory
The musl builds need libstdc++ and libgcc, and stock Alpine ships neither. Without them the binary fails inside the system loader, with dozens of mangled symbol names and nothing that mentions varsafe.
A current installer prevents this. Run as root, it installs both libraries for you; otherwise it stops and prints the command to run:
apk add --no-cache libstdc++ libgcc
To let the installer do it through sudo instead, re-run it with VARSAFE_INSTALL_PREREQS=1. It never does that on its own: a script piped from the internet should not change your system packages just because sudo happens to be available.
The installer also runs the downloaded binary once before putting it on your PATH, so an install that would fail on first run fails during installation, with the reason. If you see this error at all, you probably installed with an older install.sh; re-fetch it.
Cannot verify the release signature on this machine
Cannot verify the release signature on this machine — nothing was installed.
The installer checks each release’s signature before installing it, and needs OpenSSH 8.1 or later (ssh-keygen) or OpenSSL 3 to do so. This is not a sign of tampering: the machine has neither. Install one and re-run the installer:
apt install openssh-clientOr install openssl instead.
dnf install opensshOr install openssl instead.
dnf install epel-release && dnf install openssl3apk add openssh-keygenOr install openssl instead.
OpenSSH ships with macOS 10.15 and later; otherwise put OpenSSL 3 first on PATH.
Network and API
Cannot connect to server
The CLI could not reach the API. Check your connection, any proxy or firewall in the way, and which API the CLI is pointed at: by default https://api.varsafe.dev. To point it somewhere else, for a staging or self-hosted stack:
# Per invocation, or in CI: the variable overrides the API saved at sign-in
VARSAFE_API_URL=https://varsafe.internal.example.com varsafe whoami
# Or save it when you sign in (on login, --api-url outranks the variable)
varsafe login --api-url https://varsafe.internal.example.com
A stored login is never sent to a different API than the one it was issued by. If VARSAFE_API_URL points elsewhere, commands stop with You are signed in to … but VARSAFE_API_URL points at …: unset the variable, or sign in to that API with varsafe login --api-url.
Commands that only need to look up a project or environment can fall back to the CLI’s cached copy while offline. Anything that reads or writes secret values needs a live connection.
Rate limits
The API limits how fast one client can make requests, and answers 429 with a Retry-After header when a client goes over. If a script hits the limit, batch the work: one varsafe run per deploy rather than a varsafe get per variable.
Exit codes
Every command uses the same exit codes, so a script can tell a refusal from an outage:
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Not signed in, or the credential was rejected; or an unclassified failure |
2 |
The API could not be reached |
3 |
The command rejected its arguments, or a confirmation was required |
4 |
The project, environment or secret does not exist |
5 |
The credential is not allowed to do this |
99 |
Unexpected failure: re-run with VARSAFE_DEBUG=1 |
126, 127 |
varsafe run only: the command cannot be executed, or was not found |
Mistakes caught before a command starts (an unknown command, an unknown option, a missing argument) exit 1, not 3. varsafe run --help prints this table for the installed version.
Finding out what happened
Every secret read, change, export and sign-in is recorded in the append-only audit log: dashboard → Audit log. Filter by team, action, target or date, or search by a person’s email or a target’s name, to see exactly what a teammate, token or AI agent did. It is the quickest way to tell whether a “missing” secret was deleted, renamed, or never existed. See Audit log.
Still stuck?
- Re-run the failing command with
VARSAFE_DEBUG=1. The CLI then writes diagnostic detail to~/.varsafe/debug.log. - Errors raised by the CLI end with an
Error code:line. Include it when you ask for help. - Contact support with the command, the full error output, and your CLI version (
varsafe --version).