Skip to content

Troubleshooting

"Handled" errors are prefixed with a stable code [CODE] in the output, and the message includes a remediation (-> ...).

Error codes

AD configuration (configure-ad.ps1)

Code Meaning Remediation
LDAPS-E-CAEXPORT Unable to export the LDAPS CA (TLS + local store + certutil all failed). Enable LDAPS on the DC (server certificate in LocalMachine\My) or ADCS. See Scenario 1.
AD-E-NTAUTH Publishing the Teleport CA to NTAuth failed. Run configure-ad.ps1 as Enterprise Admin (Domain Admin is not enough). Without the CA in NTAuth: "smart card isn't supported for your account".

General API (authentication, scripts, callbacks)

Response Meaning Remediation
429 {error:'too_many_attempts', retryAfterSeconds} + Retry-After header Per-user login lockout after too many failures (in addition to the limit of 5 attempts/minute). Wait Retry-After seconds; the delay grows with each additional failure.
403 on password login TELEPORT_ONLY=true: only Teleport SSO login is allowed. Go through the Teleport application, or reinstall without --sso-only.
410 on /api/i/<id>/<key>/install.sh install.sh is served only once. Generate a new deployment.
409 on /api/i/... Deployment not ready or expired. Regenerate the deployment.
403 on /api/i/... (from a server) Not from Tenantry: an Access policy, WAF rule or country block in front of it refuses that server. See Exposure: never expose raw.
401 on /api/i/<id>/<key>/steward-bundle.sh The Steward bundle link is wrong or older than 30 minutes. Generate the install command again on the Steward page.
409 ad_output_already_received (callback) The AD output has already been received: a second write is refused. Generate a new deployment if the data must change.
422 insecure_public_base The public URL (PUBLIC_API_BASE) is not an acceptable https:// URL (localhost, Vite port...). Fix --public-url / PUBLIC_API_BASE.
422 validation_failed Invalid deployment fields. Read validation in the response.

Steward integration API (/api/steward/*)

Response Meaning Remediation
422 {ok:false, issues} (preview, apply, verify) Invalid answers (https://host[:port] URI, host:port proxy, cluster name, distinct role names, freshness 30-3600 s...). Fix the fields listed in issues (path + message).
409 {error:'would_overwrite', conflicts:[...]} (apply) A role or application with the same name exists without the label tenantry-managed: 'true'; nothing was modified. Check conflicts, rename, or confirm "Replace existing" (resends with overwrite:true).
422 reserved role name Name reserved by Teleport (access, editor, auditor, admin, tenantry, member, requester, reviewer, prefixes teleport-, bot-, preset-). Choose another name.
apply: pending:true Application created but not yet readable after 5 s (Teleport auth cache). Run Verify again.
502 on apply, steps[].name = "roles" tctl create -f of the roles failed; the app step is skipped. Read steps[].output; rules permissions of the Tenantry role (Steward integration, a), tctl version.
502 on apply, steps[].name = "app" Roles created, application registration refused. Typically access to app denied: Tenantry role without matching app_labels (Steward integration, a).
502 {error:'resource_state_unknown'} or one of the teleport_* codes above (apply, verify) The state of the Teleport resources could not be read (tctl unavailable or failing); nothing is modified or asserted. Check tctl authentication (tctl status), then retry.
verify: role <name> failed Role missing from the cluster. Run Apply again.
verify: application <name> failed Application not registered (or Teleport cache lagging). Apply, then run Verify again after a few seconds.
verify: application service failed No app service serves the application (tctl apps ls does not list it). app_service block from teleport-app-service.snippet.yaml on the agent, or resources with the label.
verify: URI failed Teleport URI differs from the expected URI. Re-apply with the correct URI.
verify: label failed The application's label does not match the roles'. Re-apply.

Fleet API (/api/nodes/*)

Response Meaning Remediation
400 Node identifier that is not a UUID, message longer than 200 characters, duration not in the list (1, 4, 12, 24, 72, 168 h or null), or unknown field. Fix the request; use the interface.
403 on lock / unlock insufficient_level: read-only technician on this client. (Another client's node answers 404.) Operator level on the client (Technicians) or an administrator.
404 not_found server-id not in the fleet (agent deleted or never joined). Refresh the page.
404 not_locked (unlock) No active lock on this node. Refresh: it may have expired or been removed.
409 protected_node The node runs Auth or Proxy (reason: protected_service): locking it would cut off the cluster; or its type is not lockable (reason: unsupported_kind). Attempt logged as denied with refused: <reason>. Do not lock it.
409 already_locked The node already has an active lock. Unlock first to change the message or duration.
502 teleport_credentials_expired The tctl identity file has expired (your credentials have expired, please log in using tsh login). Body: message + hint, never the raw tctl output. --auth identity: renew with tctl auth sign --user=<user> --format=file --out=identity --ttl=<duration>, then replace the mounted file (no restart). Long-term: --auth machine-id. --auth machine-id: tbot stopped renewing, see "Machine ID (tbot)" below.
502 teleport_access_denied Tenantry role lacks a permission (access denied to perform action "update" on "lock"). The body carries only verb and resource ([a-z_], 40 chars max). Add the rule to Tenantry role (Steward "Generated files", option allowNodeLock).
502 teleport_identity_missing The configured identity file (TELEPORT_IDENTITY_FILE) is missing or unreadable. Check the mounted volume and the path.
502 teleport_unreachable Teleport is not responding (connection refused, timeout, unknown host). Teleport service running, network and firewall between Tenantry and --auth-server.
502 teleport_unavailable Unable to read the cluster for another reason (tctl failing); never an empty list. tctl status from the container, valid identity (see "Application tctl auth").
502 lock_failed tctl lock refused. Tenantry role: lock with create and update (Client proxies).
502 unlock_failed Lock removal refused. delete permission on lock.
200 with pending:true Action done, but the Teleport auth cache did not catch up within 5 s. Refresh a few seconds later.

Common symptoms (no code)

Symptom Likely cause Action
configure-ad: "LDAPS TLS export failed … forcibly closed" LDAPS not configured (no server certificate). Install a server certificate (ADCS or self-signed), retest the port 636 handshake.
Teleport RDP: "smart card isn't supported for your account" Teleport CA missing from NTAuth and/or RDP cert template not applied to the target server. Teleport Access Policy GPO linked to the server's OU + Gateway+AD scenario (configure-ad) run (publishes the CA to NTAuth).

Installer, wizard, tunnel and local Teleport

Errors printed by scripts/install.sh (it exits non-zero and changes nothing before validation succeeds).

Message or symptom Cause Action
No option given. Run it in a terminal for the guided installation... No terminal (ssh without a tty, cron, CI) and no option. Use ssh -t, or pass the options (the equivalent command printed by the wizard).
Wizard: "No Teleport detected on this server" No Teleport container whose tctl status answers, no local tctl with /etc/teleport.yaml. Not run as root. Run with sudo. Name the container (docker ps), or choose "Elsewhere".
--teleport-local auto: several local Teleport auth services More than one local Teleport. Choose one: --teleport-local docker:CONTAINER.
tctl does not answer in <container> / tctl status failed there The container is not the auth service, or you are not root. Test it: docker exec <container> tctl status.
container <name> is only on Docker's default bridge network Names do not resolve on the default bridge. Run Teleport on a user-defined network (Compose does), or pass --auth-server ADDR:3025 and --add-host.
--teleport-local always uses --auth machine-id / --bot-token-file is not used with --teleport-local Conflicting options. Remove --auth and --bot-token-file.
tctl create of the tenantry role failed The local tctl could not create the role. Run as root. Check docker exec <container> tctl create --help; read the Teleport logs.
tctl create of the role steward-admin failed Same, for a Steward console role. Same; or create it yourself (scripts/install.sh --print-console-roles). An existing role of that name is never replaced.
the image ... prints a different tenantry role than this installer The installer and the image are not the same release (or the image was tampered with). Nothing was created in Teleport. Run the install.sh of the release you install (git checkout v<version>), or --build.
--version X.Y.Z is required / "latest" is refused First install without a release. Pass --version <x.y.z> (or --build, --image). Re-runs keep the pinned image.
the signature of ... does not verify / --require-signature: cosign is not installed cosign verify failed for the pulled digest, or cosign is missing with --require-signature. Check the version and your registry/mirror; install cosign. Do not bypass a failed verification.
--build with tctl X.Y.Z: pass --teleport-commit Only the commit of the embedded tctl version is pinned in the Dockerfile. --teleport-commit $(git ls-remote https://github.com/gravitational/teleport 'refs/tags/vX.Y.Z^{}' \| cut -f1) after checking it.
no free /29 for the edge network / Docker Pool overlaps Every candidate subnet of the edge network is in use. Pass --edge-subnet <a private /29 used nowhere else>.
Every user hits the sign-in rate limit together (behind --expose proxy) No --trust-proxy: all requests come from the proxy's address. Re-run with --trust-proxy <proxy address> (printed at the end of the install for a proxy on this server).
could not read the join token from tctl's output tctl bots add output changed or failed. The output is not shown on purpose (it may contain a token). Create the bot by hand (variants) and use --auth machine-id --bot-token-file.
--auth machine-id needs --bot-token-file on the first install Teleport elsewhere, first install, no token. Create the bot and save the token.
--tls applies to --expose local --tls with --expose proxy or cloudflare-tunnel. Drop --tls: Cloudflare or your proxy serves the certificate.
--public-url must be https://<hostname> ... with --expose cloudflare-tunnel A port or http:// in the URL. Use https://tenantry.acme.ch.
--expose cloudflare-tunnel needs --tunnel-token-file FILE on the first install No terminal to type the token. Pass --tunnel-token-file.
does not look like a tunnel token Wrong string. Copy the long base64 string after --token in the command Cloudflare shows.
--public-url must be https://name:port with --tls The URL does not match --tls-domain and --https-port. Use https://<name>:<https-port> (port 443 may be omitted).
Port 443 or 80 already in use Teleport (443) or another web server. --https-port 9443, and --no-http-redirect if port 80 is taken. The wizard does this itself.
a public CA cannot issue for this name The name ends with .local, .lan, .internal... Use a name under your public domain, or --acme-server with your own ACME server.
certificate issuance failed Wrong or under-privileged DNS token, or port 80 not reachable (HTTP-01). docker compose -p tenantry-<name> logs acme. Delete <dir>/secrets/acme-dns.env to type the credentials again. Test with --acme-server letsencrypt_test.
--dns-setting X: this variable is a secret A secret passed on the command line. Put it in --dns-credentials-file.
--dns-provider dns_xxx: name its secret variables with --dns-secret-var A provider Tenantry does not know. See Other acme.sh provider.
could not chown ... to 65532 / ... to 1000:1000 Not run as root. Re-run with sudo. cloudflared or tbot cannot read its token file otherwise.

Cloudflare Tunnel

Symptom Cause Action
cloudflared restarts or logs an authentication error Wrong, revoked or unreadable token. docker compose -p tenantry-<name> logs cloudflared. Replace the token: delete <dir>/cloudflared/tunnel-token, run install.sh again.
Error 502 or 1033 at the public name No public hostname on the tunnel, or the service is not http://tenantry:8443. Check the tunnel's Public hostname.
Public name answers without a login page The Access application is missing or does not cover the hostname. Create it first, then check the hostname.
Scripts on a client server get a Cloudflare login page (HTML) or 403 /api/i and /api/callback are behind Access. Add the Bypass application for these two paths (Exposure).
tsh login or an agent cannot join through the tunnel Access blocks non-browser clients. Letting tsh and agents through.
Teleport behind the tunnel: web UI loads but sessions fail Match SNI to Host off, or the origin certificate does not match. Turn on Match SNI to Host; use https://teleport:443.
A Steward console behind Access is "down" in Tenantry The poll is a non-browser client. Bypass or Allow for Tenantry's egress IP.

Machine ID with a local Teleport

Symptom Cause Action
tbot produced no identity after 60 s right after a local install tbot cannot reach <container>:3025 (network), or CA pins do not match. docker compose -p tenantry-<name> logs tbot. Check compose.teleport-network.yml and that the Teleport container is on that network. Re-run install.sh --teleport-local auto: it issues a new join token for the existing bot.
Token expired before the join The join token has a short lifetime. Re-run the installer: a new token is issued (tctl bots instances add tenantry).

Debugging

Useful commands

# LDAPS (from the DC or a machine that can reach it)
$h='dc1.example.local'; try { $t=[Net.Sockets.TcpClient]::new($h,636); $s=[Net.Security.SslStream]::new($t.GetStream(),$false,{$true}); $s.AuthenticateAsClient($h); "OK $($s.RemoteCertificate.Subject)"; $s.Dispose(); $t.Dispose() } catch { "KO: $($_.Exception.Message)" }

Application tctl auth

docker compose -p tenantry-<name> exec tenantry tctl status

On failure: --auth local → check the /etc/teleport.yaml + /var/lib/teleport mounts and permissions (root). --auth identity → check TELEPORT_IDENTITY_FILE (present, renewed) and TELEPORT_AUTH_SERVER. --auth machine-id → see below. Unknown certificate → --ca-file; unresolved name → --add-host. Health: curl http://127.0.0.1:8443/api/health.

Machine ID (tbot)

docker compose -p tenantry-<name> ps tbot                 # running? restarting in a loop?
docker compose -p tenantry-<name> logs --tail 100 tbot
docker compose -p tenantry-<name> exec tenantry ls -l /identity/   # identity rewritten every renewal_interval
Symptom Likely cause Action
install.sh: "tbot produced no identity after 60 s" (exit 1, token kept) Wrong, already used or expired join token; --auth-server unreachable; private CA. Read the tbot logs. Expired/used token: tctl bots instances add tenantry (new token for the same bot), save it again, re-run install.sh --bot-token-file. CA: --ca-file (applies to tbot too). Name: --add-host.
tbot logs: permission denied on /var/lib/teleport/bot, /identity-out or the token Volumes not owned by uid 1000 (tbot-init failed), or install.sh not run as root (token folder not chowned: the script warns). docker compose -p tenantry-<name> logs tbot-init; re-run install.sh as root.
tbot logs: token ... not found / already used after a re-install The tbot-storage volume was deleted: the bot lost its renewable identity and the old token is gone (single-use, deleted). New token: tctl bots instances add tenantry, then install.sh --bot-token-file.
tbot logs: renewal access denied / bot locked / generation mismatch The bot was locked or deleted, or its identity was used twice (copied volume): Teleport refuses the renewal by design. Remove the lock (tctl get locks), or recreate the bot (tctl bots rm tenantry, then the Security page commands). Never copy tbot-storage between hosts.
Dashboard / Security page: "Machine ID has not renewed ... since ..."; alert identity_not_renewed The identity file was not rewritten within 2 x renewal_interval (tbot stopped, cannot reach Teleport, or crash-loops). The current certificate works until its certificate_ttl ends. docker compose -p tenantry-<name> up -d tbot, then the logs. Once the file is rewritten the warning and the alert resolve by themselves.
"Machine ID has not produced Tenantry's Teleport credentials yet" No /identity/identity at all: tbot never joined. First row of this table.
tbot image pull fails (manifest unknown) No tbot-distroless tag for that exact --teleport-version, or no access to public.ecr.aws. Use the cluster's exact version, or --tbot-image <mirror>/tbot-distroless:<version>.