Troubleshooting
The server won’t start
Vouch fails fast: rather than starting in a half-configured state, it validates everything at boot and exits with a message naming the problem. Read the last line of output — it is almost always specific enough to act on.
The full list of fatal conditions is in Startup Validation. The ones that come up most:
No upstream IdP configured. Set VOUCH_IDPS=<slug>[,<slug>...]
At least one identity provider is mandatory. Set VOUCH_IDPS plus that slug’s
VOUCH_IDP_<SLUG>_* variables. Remember that hyphens in a slug become underscores in the variable
names: corp-saml → VOUCH_IDP_CORP_SAML_*.
Failed to configure IdP '<id>'
Discovery or metadata could not be fetched at startup. Check that the issuer or metadata URL is
reachable from the server and returns what it should:
curl -s "$VOUCH_IDP_GOOGLE_ISSUER/.well-known/openid-configuration" | jq .issuer
If the IdP uses an internal certificate authority, set VOUCH_EXTRA_CA_CERTS to a PEM bundle
containing it. If the discovery document’s issuer field differs from what you configured — even
by a trailing slash — they must be made to match.
VOUCH_JWT_SECRET must be at least 32 characters
Generate one with openssl rand -base64 48. A secret made of one repeated character is also
rejected, and one with fewer than 8 distinct bytes logs a warning.
Partial TLS configuration: set both VOUCH_TLS_CERT and VOUCH_TLS_KEY ... or neither.
Both or neither. Setting only one is always a mistake, so it is refused rather than silently
serving plaintext.
Duplicate IdP slug '<id>'
Two entries in VOUCH_IDPS (or idps[].id in S3) share a slug. Rename one.
Wildcard CORS rejected
VOUCH_CORS_ORIGINS=* is invalid. UI routes use credentialed cookie sessions, and the CORS
specification forbids wildcard origins with credentials. List origins explicitly.
issuer subdomains are claimed but document encryption is not configured
An organization claimed an issuer subdomain while a document encryption key was configured, and
that key is now absent. Per-organization signing keys are never stored in plaintext, so the server
will not start without the key that decrypts them. Restore the document_key block in your S3
configuration, or release the subdomains before starting.
Failed to fetch S3 configuration
S3 configuration is enabled and the object could not be fetched or parsed. Unlike runtime polling —
which fails open and keeps the running configuration — startup fails closed. Check the bucket name,
key, region, and that the instance role has s3:GetObject and s3:HeadObject.
Failed to start mTLS listener
The mTLS listener starts automatically whenever TLS is configured, and a bind failure on its port
is fatal. The most common cause is another process on the port; change it with VOUCH_MTLS_PORT.
The server starts but binds the wrong port.
Not an error. When TLS is configured, VOUCH_LISTEN_ADDR is ignored and the server binds 443 and
80. See Ports and Endpoints.
Port 80 fails to bind but the server keeps running.
Also expected: this is logged as a warning, not a fatal error, and you lose only the HTTP→HTTPS
redirect. On Linux, binding below 1024 needs CAP_NET_BIND_SERVICE.
Common Issues
Server Connection Issues
“Connection refused” or timeouts
- Check server health:
curl -k https://auth.example.com/health - Check DNS resolution:
dig auth.example.com - Check TLS:
openssl s_client -connect auth.example.com:443 - Check firewall rules (port 443 must be accessible)
SCIM Provisioning Issues
User not de-provisioned
- Verify the SCIM bearer token is valid and not expired
- Check the SCIM audit log for errors
- Confirm the IdP is sending DELETE requests to the correct endpoint
SCIM token rejected
- Tokens are shown once at creation and cannot be retrieved after
- Generate a new token via the admin API (
POST /api/v1/org/scim-tokens) and update the IdP configuration
Mutual-TLS Client Authentication Issues
subject mismatch for a client using tls_client_auth
The registered tls_client_auth_subject_dn must be the RFC 4514 string
representation of the certificate subject, which lists RDNs in the reverse of
their DER order. OpenSSL prints that order only when you ask for it:
openssl x509 -in client.crt -noout -subject -nameopt rfc2253
The default -subject output, the Subject: line in -text, and
-nameopt oneline all print the opposite RDN order, so pasting any of them
for a subject with two or more RDNs gives subject mismatch. For example, a
certificate issued with -subj '/O=Acme/CN=foo' prints O=Acme, CN=foo by
default but must be registered as CN=foo,O=Acme.
When the registered value matches only after reversing the RDN order, the
server logs a warning naming this as the cause — search the log for
RDN order reversed.
Spacing and attribute-name case are not significant: O = Acme, o=acme,
and O=Acme all compare equal, as does a multi-valued RDN written
CN=foo + O=Acme or CN=foo+O=Acme.
Identity Provider Issues
“Failed to fetch upstream OIDC discovery document”
- Verify the configured
VOUCH_IDP_<SLUG>_ISSUERis correct and reachable:curl -s $VOUCH_IDP_<SLUG>_ISSUER/.well-known/openid-configuration | jq .issuer - Verify the issuer URL uses HTTPS (HTTP is only allowed for
localhost) - Confirm the server can make outbound HTTPS requests (firewall, proxy)
“Issuer mismatch” during OIDC discovery
- The
issuerfield in the discovery document must exactly matchVOUCH_IDP_<SLUG>_ISSUER(trailing slashes matter) - Some providers require a trailing slash (e.g., Auth0:
https://tenant.auth0.com/) - Entra
/organizations/v2.0is special-cased — its{tenantid}template issuer is accepted - Entra
/common/v2.0is rejected at startup; use/organizations/v2.0or a single-tenant URL (see Microsoft Entra ID)
“Failed to fetch SAML IdP metadata”
- Verify the configured
VOUCH_IDP_<SLUG>_METADATA_URLis correct and reachable - Verify the URL returns XML, not an HTML login page
- Confirm the server can make outbound HTTPS requests
SAML signature verification errors
- Confirm the IdP’s signing certificate in the metadata is current and not expired
- Confirm the server clock is NTP-synchronized — SAML assertions have time-based validity windows (5 minutes of skew tolerance is common)
- Verify the IdP assertion signing algorithm matches what the server expects
“Duplicate IdP slug”
- Every entry in
VOUCH_IDPS/idps[].idmust be unique. Rename one of them.
Debug Logging
Enable verbose logging for troubleshooting:
# Server
RUST_LOG=debug vouch-server
For component-specific logging:
RUST_LOG=vouch_server=debug
Getting Help
- GitHub Issues — Bug reports
- GitHub Discussions — Questions
- Security Issues — Security vulnerabilities