Troubleshooting
Server Starts but Registration or Login Returns 500
Symptoms: /api/v1/health returns {"status":"ok"}, but creating an account or any real request fails with an INTERNAL / 500 error. Logs mention a missing relation or table.
Cause: the database migrations were never applied. The health endpoint does not touch the schema, so the server can start and report healthy against an empty database. The server command does not auto-migrate.
Fix: apply the migrations, then retry:
# Full stack
docker compose exec -T vaultctl /usr/local/bin/vaultctl migrate up
# Simple compose
docker compose -f docker-compose.simple.yml exec -T vaultctl /usr/local/bin/vaultctl migrate upThe one-line installer does this for you. migrate up is idempotent — safe to re-run after every upgrade.
Installer Cannot Find or Start Docker (macOS)
Symptoms: the installer reports "Docker daemon is not running", or docker is not found on a fresh macOS machine.
- Homebrew required: on macOS the installer uses Homebrew to install a headless runtime (
colima+ thedockerCLI). Install Homebrew (opens in a new tab) first, then re-run. - Daemon not running: the installer runs
colima startautomatically. To do it manually:colima start docker info # should now succeed - PATH: Homebrew installs to
/usr/local/bin(Intel) or/opt/homebrew/bin(Apple Silicon). Ifdockeris "not found" in a non-interactive shell, ensure that directory is on yourPATH. - Docker Desktop: if you already run Docker Desktop, the installer uses it instead of colima — just make sure it is started.
Cannot Connect to Server
Symptoms: Browser shows "connection refused", "ERR_CONNECTION_TIMED_OUT", or "unable to reach server".
Check these in order:
-
Server is running:
docker compose ps # or systemctl status vaultctl -
Correct URL: Ensure you are using
https://(nothttp://) and the correct port. The default is443if behind a reverse proxy, or8080for the raw server. -
TLS certificate: If using a self-signed certificate, your browser may block the connection. Accept the certificate or configure a trusted CA.
-
Firewall: Ensure the port is open:
# Check if the port is listening ss -tlnp | grep 8080 -
Reverse proxy: If using Caddy or nginx, check the proxy logs:
docker compose logs caddy # or journalctl -u nginx
Login Fails
Symptoms: "Invalid credentials" error after entering correct password.
- Caps Lock: Verify Caps Lock is off. The master password is case-sensitive.
- Account locked: After 5 consecutive failed attempts, the account is locked for 15 minutes (configurable via
LOCKOUT_DURATION). Wait and try again. - KDF mismatch: If you changed KDF parameters after registration (not recommended), the client may derive a different auth hash. Use the same parameters that were set during account creation.
If your account is locked, you will receive an ACCOUNT_LOCKED error. The lockout expires automatically — there is no manual unlock.
Slow Login
Symptoms: Login takes 2-5 seconds or more.
This is expected behavior. vaultctl uses Argon2id with 64 MB of memory and 3 iterations for key derivation. This is intentionally slow to make brute-force attacks impractical.
- 2-5 seconds is normal on modern hardware.
- Older or low-memory devices may take longer.
- Do not reduce KDF parameters to speed up login — this weakens security.
Browser Extension Not Autofilling
Symptoms: The extension icon appears but does not fill in credentials.
-
Check permissions: Ensure the extension has permission to access the current site. Click the extension icon and check site access settings.
-
Check URI match: The extension matches saved items by URI. If the saved URI is
https://example.com/loginbut you are onhttps://example.com/app/login, the match may fail. Edit the item and update the URI, or add multiple URIs. -
Multiple matches: If multiple items match, the extension shows a dropdown instead of autofilling. Click the extension icon and select the correct item.
-
Iframe isolation: Some sites use iframes for login forms. The extension may not have access to iframe contents depending on browser security settings.
429 Rate Limited
Symptoms: API returns {"error": {"code": "RATE_LIMITED", "message": "too many requests"}}.
The server enforces rate limits to prevent abuse:
| Scope | Default Limit |
|---|---|
| Per IP | 60 requests/min |
| Per email (auth endpoints) | 5 attempts / 15 min |
Resolution:
- Wait for the
Retry-Afterheader value (in seconds) before retrying. - If you are hitting the per-IP limit from scripts or automation, increase
RATE_LIMIT_RPMin the server configuration. - If you are hitting the per-email limit, wait 15 minutes or adjust
AUTH_RATE_LIMIT_WINDOW.
500 Internal Server Error
Symptoms: API returns {"error": {"code": "INTERNAL", "message": "internal server error"}}.
-
Check server logs:
docker compose logs vaultctl --tail 100 # or journalctl -u vaultctl --since "5 minutes ago" -
Database connectivity: Verify PostgreSQL is running and the
DATABASE_URLis correct:docker compose exec db pg_isready -
Missing environment variables: Ensure all required env vars are set. See Server Configuration.
-
Disk space: Check available disk space. PostgreSQL may refuse writes if the disk is full.
-
Report the issue: If the error persists, open an issue on GitHub (opens in a new tab) with the relevant log output (redact any sensitive values).
Server logs may contain request metadata. The LOG_REDACT_FIELDS environment variable controls which fields are redacted. Ensure sensitive fields are redacted before sharing logs publicly.