# Troubleshooting and FAQ

> Symptoms, causes and fixes for the widget, siteverify and the gateway, with the error codes you will see and answers to common questions.

Start with the error code: the SDK rejects with `err.code`, siteverify
answers `error`, and the gateway sets `X-AgentGate-Reason`. Every code is on
[Error codes](/docs/error-codes); the common ones are below.

## Widget and SDK

| Symptom | Code | Likely cause | Fix |
| --- | --- | --- | --- |
| Nothing happens, console shows `AgentGate is not defined` | | the script did not load | check the `src` URL and CSP `script-src` |
| Verification fails at once | `origin_denied` | the page's origin is not allowed for the site key | add the exact origin (scheme, host, port) to the site; use [testing keys](/docs/testing) on localhost |
| Verification fails at once | `site_invalid` | wrong or missing site key | copy the key from the console |
| Verification fails at once | `action_invalid` | the action is not configured for the site | add the action to the site, or fix `data-action` |
| Verification fails | `network` | offline, DNS, TLS, or CSP `connect-src` blocks the endpoint | allow the endpoint in `connect-src` ([CSP](/docs/content-security-policy)) |
| People are asked for the check more than expected | | `init()` is not called at page load (`agentgate:sdk:late_init`), the instrumentation script is blocked by CSP, or rules are strict | call `AgentGate.init()` early; allow the endpoint in `script-src`; review the decisions in monitor mode |
| The check dialog never closes | `canceled` after Escape | the person closed it | offer a retry |
| Verification stops after a while | `timeout` | slow network or a long visible check | raise `timeout` or `checkTimeout` |
| Frequent failures from one network | `rate_limited` | more than 60 challenges or 120 verifications per minute from one address | wait for `Retry-After` (60 s); the per-address limits are fixed |
| Automated tests fail or see the check | `challenge_failed` | browser automation is detected, as designed | use `site_test_always_pass` in tests ([Testing](/docs/testing)) |

## Server-side validation

| Symptom | Code | Likely cause | Fix |
| --- | --- | --- | --- |
| Every call fails | `invalid_credential` (401) | wrong, revoked or another site's secret, or `Authorization` without `Bearer ` | check `AGENTGATE_SECRET`; create a new secret if lost |
| Every call fails | `invalid_request` (400) | form-encoded body, missing `expectedAction`, or a bad `requestId` | send JSON with `token` and `expectedAction` |
| Tokens rejected | `invalid_token` (422) | not a token (empty field, truncated), another AgentGate's token, or a test token with a real secret | check the field name `agentgate_token`; do not mix test and real keys |
| Tokens rejected | `expired_token` (422) | redeemed more than two minutes after issue | verify at submit time; redeem promptly |
| Tokens rejected | `action_mismatch` (422) | `expectedAction` differs from the widget's `data-action` | use the same action name on both sides |
| Tokens rejected | `origin_mismatch` (422) | `expectedOrigin` differs from the page origin (www, port, http/https) | compare with `origin` in a successful answer |
| Second submit fails | `token_used` (409) | the token was redeemed already: a double submit, a retry without `requestId`, or a test with `ags_test_token_spent` | send `requestId` and retry with the same one; the widget verifies again for each submission |
| Occasional failures | `unavailable` (503) | AgentGate's store was unavailable | retry once with the same `requestId` after `Retry-After` |

## Gateway

| Symptom | Reason | Likely cause | Fix |
| --- | --- | --- | --- |
| Every request is `403` | `invalid_credential` | the secret in nginx or the middleware is wrong | update the credential include and reload nginx |
| Every request is `403` | `invalid_request` | the adapter does not send `X-Original-*` headers | use the tested configuration ([nginx](/docs/gateway-nginx)) |
| Browser routes answer `401` | `receipt_required` | the page did not send `X-AgentGate-Token` | send the token as a header; form fields do not reach `auth_request` |
| Browser routes answer `401` | `invalid_token` | a test token, or a token for another site | use a real site key on pages behind a real gateway |
| Clearance not accepted | `origin_mismatch`, `expired_clearance` | the page and the protected route are on different origins, or the clearance expired | serve both from one origin; verify again |
| Clients get `503` | `service_unavailable` | AgentGate unreachable, slow or failing (enforce mode fails closed) | check `GET /readyz` on your AgentGate endpoint (`503` while it cannot decide); enforce-mode sites fail closed by design, see [When AgentGate fails](/docs/monitor-and-enforce#when-agentgate-fails) |
| Clients get `429` | `rate_limited` | over `GATEWAY_IP_PER_MINUTE` or an agent quota | raise the budget or review the rule |

## FAQ

### Is the widget enough on its own?

No. The widget produces a token; only [`/v1/siteverify`](/docs/siteverify)
(or the gateway) enforces anything. A request that reaches your backend
without being validated is not protected.

### Do I need a separate site for staging?

A site can list several origins, so staging can share the production site.
A separate site in monitor mode keeps staging decisions out of your
production dashboard. For CI, use the [testing keys](/docs/testing).

### Why did a person get the check?

Open the decision in the dashboard (the `decisionId` is in the SDK result
and the siteverify answer): it lists the labels and the rule that asked for
the check. Common causes are `sdk_late_init`, a blocked instrumentation
script, VPN or datacenter addresses, and browser extensions that automate
the page.

### Can people who cannot use a mouse pass the check?

Yes. Press and hold works with Space or Enter held on the focused button,
and "Verify another way" needs no pointer, timing or puzzle: the browser
does extra work during a ten-second wait.

### Does AgentGate work without JavaScript?

The browser check needs JavaScript. For clients without it (APIs, native
apps, agents) use the [gateway](/docs/gateway) with machine routes and
[signed agents](/docs/signed-agents).

### Does AgentGate set cookies?

The widget sets none. The `agentgate_clearance` cookie is set only for
clearance actions when AgentGate's browser API is served from your own
origin. The console uses a session cookie for signed-in customers.

### What does AgentGate store about visitors?

Timings and counts, never what is typed; see the
[privacy notice](/docs/privacy).

### How do I report a security issue?

See [/.well-known/security.txt](/.well-known/security.txt) and the
[security testing policy](/hack).
