--- title: "MCP guide: troubleshooting" description: Every error code a OneHazel connect tool can return, what it means and what to do, plus the address checks, catalogue rejections and your PAM's own error codes. --- # Troubleshooting When a `connect_*` tool fails, your agent sees a code such as `CONNECT_INVALID_URL`. This page lists every code those tools can return. It also lists every reason a test run can end `errored`. Then come the adapter's own answers, its `env_refused`, and why it can refuse to start. The code and reason lists are built from the OneHazel source. A code or reason missing there is one OneHazel does not send. ::: tip What you need before you start - The exact code your agent reported. Ask it: "What was the error code and message?" - For a failed test run, the run's evidence. Ask your agent to call `connect_conformance_evidence` for that run. It shows every request OneHazel sent and every answer your casino gave. Secrets are hidden. ::: ## Every code | Code | What it means | What to do | |---|---|---| | `MCP_CONNECT_NOT_ENABLED` | The key your agent uses was not created for Connect. | This key has no Connect scope. Create one in app.onehazel.com under Connect casino, Integrate with AI (the API Keys page cannot add it). | | `CONNECT_DISABLED` | Connect is switched off for this OneHazel environment. | Ask for access through the chat button in the OneHazel app. Once it is on, wait 30 seconds and try again. | | `MCP_TOOL_NOT_FOUND` | Your agent called a tool name the OneHazel server does not have. Usually it is a typo. | Ask your agent to list the OneHazel tools and use a name from that list. | | `MCP_RATE_LIMITED` | Your agent called one tool too often in a minute, or too many times at once. | For the per-minute limit, wait the `retryAfterSeconds` the answer gives, then try again. The too-many-at-once answer carries no such number: wait for your agent's other calls to finish, then try again. | | `MCP_INPUT_INVALID` | Your agent sent the tool a value it does not accept, or left one out. | Ask your agent to reread the tool's description and resend. The error names each wrong field. | | `VALIDATION_ERROR` | A value is missing or in the wrong form. For example, a wallet registered without a test player. | Read the message: it names the value. Give your agent that value and try again. | | `CONNECT_INVALID_URL` | OneHazel refused the address without trying it. It is not public https, or its name does not resolve. | Use a public https address with a working DNS record. See the section below this table. | | `CONNECT_ENDPOINT_UNREACHABLE` | The address resolves, but nothing healthy answered `/healthz` within 3 seconds. Nothing was stored. | Start the adapter and check both `/healthz` probes answer 200. Then register again. | | `CONNECT_MODULE_NOT_REGISTRABLE` | That module does not take an address. Only the modules your casino serves do. | Use one of `wallet`, `player`, `webhook.receive`, `payments.intent`. | | `CONNECT_MODULE_NOT_REGISTERED` | Your agent tried to test or simulate a module with no registered address yet. | Register that module first. The `wallet` module also needs `testPlayerId` and `testGame`; the `player` module needs `testPlayerId` and `restrictedPlayerId`. | | `CONNECT_MODULE_IN_USE` | An active connection needs this module, so it cannot be removed. Nothing was removed. | Pause each connection the message names: open it and click **Pause** at the top right of the page. Then try again. | | `CONNECT_TEST_GAME_REJECTED` | Your casino refused the test game when the wallet test opened its first session. Nothing was charged: the session was refused before any bet. | Give your agent a game that is active in your catalogue, with the provider slug and game code your launch endpoint accepts. Registering it again keeps the secrets, so no restart. | | `CONNECT_RUN_NOT_FOUND` | No conformance run with that id exists for your account. | Ask your agent to call connect_status and use a run id from its answer. | | `CONNECT_CONNECTOR_NOT_FOUND` | There is no public marketplace connector with that key. | Use a key from `connect_list_marketplace`. | | `NOT_FOUND` | Something the tool needs does not exist. Usually the module was never registered. | Register the module first, or ask your agent to call connect_status. | | `RATE_LIMITED` | You reached an hourly limit: 10 conformance runs or 10 simulated rounds. | Wait for the hour to pass. Meanwhile your agent can fix what the last run showed. | | `DUPLICATE_CONNECTION` | This connector's connection is in your Trash, or another connection holds the same credentials. | If the message mentions Trash, restore it from Trash. Otherwise check the values you gave. | | `CONFLICT` | The connection is active, so the tool will not change it. Nothing was saved. | Change a live connection's keys yourself, on its Credentials tab in the app. | | `CONNECTION_NOT_FOUND` | There is no inactive connection for that connector yet. | Ask your agent to create it with connect_activate, then set the credentials. | | `CREDENTIAL_DECRYPT_FAILED` | OneHazel could not read the credentials already stored on the connection. Nothing was changed. | Report it through the chat button in the OneHazel app, with the connection id. | | `CREDENTIAL_ENCRYPT_FAILED` | OneHazel could not store the credentials safely, so it saved nothing. | Try again in a minute. If it repeats, report it through the chat button in the OneHazel app. | | `INTERNAL_ERROR` | Something went wrong inside OneHazel. Your setup did not cause it. | Try again in a minute. If it repeats, report it through the chat button in the OneHazel app, with the time and tool name. | The full list of OneHazel codes is on the [error reference](/reference/errors). ## A test run that ends errored A test run either passes, fails, or ends `errored`. Errored means the run could not reach a verdict, so it proves nothing either way. The run then carries one of these reasons. Ask your agent for the reason and the message. | Reason | What the run says | What it means | What to do | |---|---|---|---| | `endpoint_missing` | Only the reason, no message. | The module had no registered address when the run started. It was removed after the run was asked for. | Ask your agent to register the module again. After a removal that mints new values: copy them into `onehazel.env`, restart the adapter, then run the test again. | | `ssrf_blocked` | Only the reason, no message. | OneHazel refused to call the address. At run time it was not https, or its name pointed at a private address. | Point the name at a public address and serve https. If the address changed, register again: that keeps the secrets, so no restart. Then run the test again. | | `missing_input` | \[module\] conformance needs \[field\] on the \[module\] endpoint. Register the \[module\] endpoint again with \[field\] set (connect_register_endpoint, or POST /operators/me/connect/endpoints), then run conformance again. | A value the test needs was never registered: a test player, a restricted test player or the test game. | Give your agent the value the message names. It registers the module again, which keeps the secrets, and reruns the test with no restart. | | `secret_unavailable` | The reason and a short detail, with secrets hidden. | OneHazel could not load the module's secret for the run. Your setup did not cause it. | Run the test again in a minute. If it repeats, report it through the chat button in the OneHazel app, with the run id. | | `profile_threw` | The reason and a short detail, with secrets hidden. | OneHazel's test runner failed while it ran. The run carries the runner's own error, with secrets hidden. | Run the test again. If it repeats, report it through the chat button in the OneHazel app, with the run id. | | `test_game_rejected` | The game you declared was rejected by your casino, check provider_slug and game_code. | Your casino refused the test game when the wallet test opened its first session. Your casino's status and error code follow the message. | Give your agent a game that is active in your catalogue and allowed for test players. Registering it keeps the secrets, so no restart. See the test game section below. | | `wallet_route_not_found` | Your wallet URL answered 404 with no contract error body, check the base URL. | Nothing at the registered wallet address speaks the contract. Usually the address is the host only, without the path to the provider routes. | Check the registered wallet address is the full path. Ask your agent to register it again, which keeps the secrets, then run the test again with no restart. | | `enqueue_failed` | Only the reason, no message. | OneHazel could not queue the test after it recorded the run, so no test ever started. Your agent's call answered `INTERNAL_ERROR`. Your setup did not cause it. | Ask your agent to run the test again in a minute. If it repeats, report it through the chat button in the OneHazel app, with the run id. | | `no_scenarios_ran` | Only the reason, no message. | No test ran at all, so the run proves nothing. It never counts as a pass. | Ask your agent to call `connect_conformance_evidence` for the run. It shows why each test was skipped. | In a message, `[module]` and `[field]` stand for the real module and value names. ## The adapter's own answers Your adapter answers some calls itself, before your PAM sees them. A failed test run's evidence shows the answer: its status, its `code` and its `message`. These five are the common ones: | The adapter answered | What it means | What to do | |---|---|---| | 401, code `unauthorized` | The callback key OneHazel sent is not the one the adapter holds. Usually `onehazel.env` still has the stand-in values from before the first register. | Copy each module's values from its file under `.onehazel/` into `onehazel.env`. Restart the adapter, then run the test again. | | 401, code `signature_invalid` | The signing secret does not match, for the same reason. Or the host's clock is more than 5 minutes wrong. | Same as above. If the values are right, set the host's clock. | | 404, message `no such route` | The settings file has no section for that module. Or the registered address carries a path the adapter does not serve. | Add the module under `modules` in `onehazel-adapter.json`, run the config check and restart the adapter before the next test. Or ask your agent to register the adapter's base address again: that keeps the secrets, so no restart. | | 502, code `unavailable` | Your PAM answered, but the adapter cannot use the answer. It may be a redirect or a body that is too large. Or a player record lacks a usable id or a field. The `message` says which. | Check the PAM address and player route in the settings file against a real answer from your PAM. After a settings change, restart the adapter before the next test. | | 503, code `unavailable` | Your PAM did not answer at all. For `webhook.receive`, also: the dedup store (Redis) did not answer, or your PAM's event sink did not accept the delivery. The `message` says which. | Check the PAM address, and that the adapter's host can reach it. For `webhook.receive`, check `ONEHAZEL_ADAPTER_REDIS_URL` and the sink address. | The stand-in values are on [Your casino](/connect/mcp/your-casino), step 4. Step 5 there shows the restart line, with Docker and without. The adapter reads its settings file and `onehazel.env` only when it starts. So after any change to either, your agent asks you to restart the adapter before it runs the test again. It is told: > If your fix changed onehazel-adapter.json or onehazel.env (testPlayerIds after env_refused, the player route, the wallet testGame, a module section missing behind 404 no such route), the adapter only reads them when it starts: ask your human to restart it (with Docker, run the start line again plus --force-recreate; without Docker, stop the adapter process and run its npx start line again with the new values in the environment) and confirm both /healthz checks answer 200 before you run conformance again. A fix made only by registering again (an address, a test player or the testGame) changes only OneHazel's registration and needs no restart; the same testGame changed in onehazel-adapter.json needs the restart. ::: info What you should see The next test run gets past the first call. The evidence no longer shows the adapter's 401 or 404. ::: ## The adapter will not start The adapter checks its settings and variables before it listens. When something is wrong, it prints one line to its error output and stops. Then neither `/healthz` check answers. Read the line on the host: ```bash docker compose logs onehazel-adapter ``` `onehazel-adapter` is the service name in your `docker-compose.yml`. Without Docker, the line is in the terminal where you started the adapter. It starts with `connect-adapter: refusing to start:`, followed by the reason: - `missing environment variable` and the names. Add a line for each to `onehazel.env`. Before the first register, stand-in values are enough. - A variable that is set but has the wrong shape: - `must hold 1 or 2 comma-separated whsec_ values`: a signing secret line holds something else. Often the callback key was pasted into the signing line. Each `..._SIGNING_SECRETS` value starts with `whsec_`; two values are separated by a comma, with no spaces inside a value. - `must be set` for a `..._CALLBACK_KEY`: the line is there but empty. Copy the callback key from the module's file under `.onehazel/`. - `must hold the native auth header value on one line`: the PAM token has a line break in it. Copying it across two lines does that. Put it on one line. - A problem in the settings file. Run the config check from step 3 of [Your casino](/connect/mcp/your-casino) and give the output to your agent. - Your PAM answered 4xx when the adapter read the first test player. The adapter reads that player once at startup. Check the id is in your PAM, and check the player route. - A Redis address it cannot use, for `webhook.receive`. Check `ONEHAZEL_ADAPTER_REDIS_URL` starts with `redis://` or `rediss://`. ::: info What you should see After the fix and a restart, both `/healthz` checks answer 200. ::: ## The adapter refused a test player: env_refused Your adapter answers OneHazel's test calls only for the players its settings list as `testPlayerIds`. For any other player it answers `player_unknown` with this message, and logs the outcome `env_refused`: > `env_refused: player not in testPlayerIds` Your agent follows this rule when it writes the settings: > testPlayerIds is required whenever modules includes wallet or player: list your test player ids, because X-OneHazel-Env: test is refused for any other player with player_unknown and the message "env_refused: player not in testPlayerIds". What to do: ask your agent to add the player id to `testPlayerIds` in `onehazel-adapter.json`. One process reads that one file, so the id goes in both lists: `modules.wallet.testPlayerIds` and `modules.player.testPlayerIds`. Run the config check, restart the adapter, then tell your agent to run the test again. Without the restart the adapter still holds the old list, and the test fails the same way. ::: info What you should see The next test run gets past the player calls. The adapter's log no longer shows `env_refused` for that player. ::: ## Address refused, or nothing answering? Registering checks the address twice, in this order: 1. **Does the name resolve to a public address?** If not, the answer is `CONNECT_INVALID_URL` (status 400). OneHazel does not try to reach it at all. You see this when the host has no DNS record yet. 2. **Does something answer `GET /healthz`?** The name resolves, but nothing answers within 3 seconds, or it answers with a 5xx. Then the answer is `CONNECT_ENDPOINT_UNREACHABLE` (status 409). Nothing is stored. Your agent can pass `allowUnreachable: true` to register before the adapter runs. That skips the second check only. A name that does not resolve is always refused. ::: info What you should see After you fix DNS or start the adapter, register again. The module then shows as **Registered**. ::: Registered an address that is wrong, but reachable? Your agent registers the module again with the right address. That keeps the module's secrets, so you copy nothing and do not restart the adapter: > Registering a module that is already registered keeps its signing secret and callback key (the result says secretUnchanged: true and carries no secret), so fixing an address, a test player or the test game this way changes only OneHazel's registration and needs no adapter restart; only connect_rotate_secret, or a different callbackKey, replaces them. ## Your casino refused the test game A test or a simulated round opens every game session with your own test game, the `testGame` your agent registered with the wallet. The register step asks for it like this: > Name one active game in your catalogue that may be used for test rounds (provider slug and game code as your PAM knows them) and register it with the wallet as testGame: { provider_slug, game_code }. Before a `wallet` test run, OneHazel opens one session with that game. If your PAM refuses it, the run stops at once with this text, followed by your casino's status and error code: > The game you declared was rejected by your casino, check provider_slug and game_code. Your agent then asks you this, word for word: > Please name one active game in your catalogue that may be used for test rounds (provider slug and game code as your PAM knows them), because your casino rejected the testGame registered with the wallet. Registering the wallet again with the new game changes only OneHazel's registration, so you do not restart the adapter for that. If your agent also changes `testGame` in `onehazel-adapter.json`, restart the adapter: it reads that file only when it starts. ::: info What you should see After your agent registers a game that is active in your catalogue and allowed for test players, the next run gets past the session start. ::: ## Your PAM's own error code When your PAM refuses a call, the adapter turns the refusal into a contract error. Since adapter 0.2.1 it also passes on your PAM's own status and code. They arrive as `details.native_status` and `details.native_code`. OneHazel shows them in the test evidence and never acts on them. Ask your agent for the failing test's `native_status` and `native_code`. Your own PAM returned them, so your PAM's logs explain them. A code the adapter does not know becomes `invalid_request`. Your agent can map it to the right contract code in the adapter's settings. ::: info What you should see In the evidence, your PAM's own status and code next to the contract error. For example, `402` and `INSUFFICIENT_BALANCE`. ::: ## Still stuck Start a new chat and paste the one line from [Install](/connect/mcp/install) again. Your agent rebuilds its picture from `connect_status` and picks up where it stopped. Still stuck? Use the chat button in the OneHazel app. Give the code, the time and the tool name.