# Wallet link and delegation error codes

> Gatewayz wallet link and delegation errors return an HTTP status, a stable code and a remedy. 400 means the nonce expired: request a new one. 401 means the CIP-8 signature, address, key, payload or network did not match: re-sign. 402 means credits ran out. 409 means the wallet is linked elsewhere. 451 means eligibility. 503 means retry later.

**In one line:** Branch on the code, not the message: 400 and 401 mean re-sign, 503 means retry later, 409 and 451 mean stop and ask.

Every error from the Gatewayz delegation and wallet link API carries three things: an HTTP status, a stable machine-readable `code`, and a `remedy` that says what to do next. An agent should branch on `code`: `400` and most `401` codes mean request a fresh nonce and sign again, `503` means retry later, `402` means add credits, and `409` or `451` mean stop and hand the decision to the account owner. The full list is also published as `/yield/errors.json`.

## Key takeaways

- Branch on the `code` field, never on the human-readable message, which may change.
- `400 nonce_missing_or_expired` and the `401` signature codes are fixed by requesting a new nonce and signing the exact message again with the right stake key.
- `503` codes are temporary: retry with backoff, and never re-sign because of them.
- `409 wallet_linked_to_other_account`, `451 region_restricted` and `401 script_stake_address_unsupported` will not succeed on retry; stop and report.
- `402 insufficient_credits` happens on inference calls, when the 1% you pay or a request after the discount runs out exceeds your credits.

## What error codes can the API return?

Thirteen codes across six HTTP statuses. The table is generated from the same file as `/yield/errors.json`, so the codes and remedies here always match what the API sends.

| Status | Code | When | Remedy |
| --- | --- | --- | --- |
| 451 | `region_restricted` | The request comes from the United States or Canada, or the account was marked as being there. | Not available. Leaving the program is never blocked. |
| 451 | `attestation_required` | The account has not confirmed it is not a US or Canadian person. | Send not_us_ca_person: true with the nonce or link call, or POST /delegation/eligibility. |
| 400 | `nonce_missing_or_expired` | The signed nonce is unknown or older than its expires_at. | Request a new nonce and sign it again. |
| 401 | `invalid_signature` | The CIP-8 signature does not verify. | Sign the exact message returned by the nonce call with the stake key. |
| 401 | `address_mismatch` | The signed address is not the stake address in the request. | Sign with the stake key of the stake_address you sent. |
| 401 | `key_address_mismatch` | The COSE key does not belong to the stake address. | Send the COSE_Key your wallet returned with the signature. |
| 401 | `payload_mismatch` | The signed payload is not the issued message. | Sign the message exactly as returned, without changes. |
| 401 | `network_mismatch` | The stake address is for a different Cardano network than the API. | Use a mainnet stake1 address on mainnet. |
| 401 | `script_stake_address_unsupported` | The address is a script stake address (stake17...). | Use a key-hash stake address (stake1u...). |
| 409 | `wallet_linked_to_other_account` | The stake address is already linked to another Gatewayz account. | Use that account, or unlink it there first. |
| 503 | `eligibility_unavailable` | Eligibility could not be read or stored. | Retry later. |
| 503 | `wallet_auth_unavailable` | Wallet linking is temporarily unavailable. | Retry later. |
| 402 | `insufficient_credits` | The 1% you pay per request, or a request after the discount runs out, exceeds your credits. | Top up credits or wait for the next discount. |

## How should an agent react to each status?

Use this table as the decision rule. "Re-sign" means: request a new nonce, sign the new `message` with the stake key using [CIP-8](/yield/glossary#cip-8), and call link again.

| Status | Action | Retry automatically? | Escalate to a human? |
| --- | --- | --- | --- |
| 400 | Re-sign with a new nonce | Yes, once | Only if it repeats |
| 401 | Fix the input named by the code, then re-sign | Once, after fixing | If the same code repeats, or for `script_stake_address_unsupported` |
| 402 | Stop spending; top up or wait for the next discount | No | Yes, the owner adds credits |
| 409 | Stop | No | Yes, the owner decides which account keeps the wallet |
| 451 | Send the attestation if the code is `attestation_required`; otherwise stop | Only for `attestation_required` | Yes for `region_restricted` |
| 503 | Wait and retry the same call | Yes, with backoff | If it persists |

Software is often the first and only reader of an error, which is why every code has a remedy written for it. [Who reads the error?](/learn/who-reads-the-error) explains the design.

## What does a 400 error mean?

A `400` means the nonce you signed is unknown or older than its `expires_at`. The fix is always the same: request a new nonce and sign it again.

`nonce_missing_or_expired` usually means the signing step took too long, for example while waiting for a human to approve a wallet prompt, or that the agent reused a nonce from an earlier attempt. Nonces are single-use: request one immediately before signing, and never cache them.

## What does a 401 error mean?

A `401` means the CIP-8 proof did not match what the API issued or what you claimed. Each code names the part that is wrong, so fix that part, then re-sign with a fresh nonce.

| Code | What went wrong | Fix |
| --- | --- | --- |
| `invalid_signature` | The COSE_Sign1 does not verify | Sign the exact message from the nonce call with the stake key |
| `address_mismatch` | The address inside the signature is not the `stake_address` you sent | Sign with the stake key of that stake address, not a payment key |
| `key_address_mismatch` | The COSE_Key does not belong to the stake address | Send the COSE_Key the wallet returned with that signature |
| `payload_mismatch` | The signed bytes are not the issued message | Hex-encode the UTF-8 message exactly as returned, with no trimming or reformatting |
| `network_mismatch` | The stake address is for a different Cardano network than the API | Use a stake address for the API's network: `stake1...` on mainnet |
| `script_stake_address_unsupported` | The address is a script stake address (`stake17...`) | Use a key-hash [stake address](/yield/glossary#stake-address) (`stake1u...`); do not retry with the same address |

The most common cause in browser wallets is `payload_mismatch`: [CIP-30](/yield/glossary#cip-30) `signData` expects hex-encoded bytes, so passing the raw string or re-encoding it changes what gets signed. The [quickstart](/yield/agents/quickstart) shows the correct encoding.

## What does a 402 error mean?

A `402 insufficient_credits` means an inference request costs more than your account's credits can cover. While the [inference discount balance](/yield/glossary#inference-discount-balance) lasts you pay 1% of [list price](/yield/glossary#list-price) from credits; once it is used up, you pay the full price.

Do not retry in a loop. Either the owner tops up credits, or the agent waits for the next discount to be credited after a finished epoch. Check `GET /delegation/rewards` for the balance before resuming. An agent that hits `402` often is a sign it needs a spend ceiling; see [Spend ceilings for unattended agents](/learn/spend-ceilings-for-unattended-agents).

## What does a 409 error mean?

A `409 wallet_linked_to_other_account` means the stake address is already linked to another Gatewayz account. A stake address can belong to only one account at a time.

This is not something an agent should resolve on its own. Either use the account that already holds the wallet, or have that account unlink it first. Retrying will not change the outcome.

## What does a 451 error mean?

A `451` is about eligibility. `attestation_required` means the account has not confirmed it is not a US or Canadian person; `region_restricted` means the program is not available to this account.

Not available to US or Canadian persons. Every participant must confirm they are not a US or Canadian person before linking a wallet.

For `attestation_required`, send `not_us_ca_person: true` with the nonce or link call, or call `POST /delegation/eligibility`; only send it if it is true. For `region_restricted`, stop: the program is not available. Leaving the program is never blocked, so a wallet can always redelegate elsewhere.

## What does a 503 error mean?

A `503` means a backend dependency is temporarily unavailable: `eligibility_unavailable` when eligibility could not be read or stored, `wallet_auth_unavailable` when wallet linking is down.

Retry the same call later with exponential backoff. Nothing about your request is wrong, so do not request a new nonce or re-sign because of a `503`; if the nonce expires while you wait, the next attempt will return a `400` and you re-sign then.

## Frequently asked questions

### What does invalid_signature mean when linking a Cardano wallet?

The CIP-8 signature you sent does not verify against the message Gatewayz issued. Request a new nonce, sign its exact `message` with the stake key of the address you are linking, and send the COSE_Sign1 and COSE_Key the wallet gives you.

### Should an agent retry a 503 from the wallet link API?

Yes. A `503` (`eligibility_unavailable` or `wallet_auth_unavailable`) is temporary, so retry the same call with backoff. Do not re-sign because of it; only re-sign if a later attempt fails with an expired nonce.

### Why is my stake17 address rejected?

Addresses starting with `stake17` are script stake addresses, which the program does not support. Use a key-hash stake address, which starts with `stake1u` on mainnet; retrying with the same script address will always fail.

### What should an agent do on 402 insufficient_credits?

Stop sending inference requests and report to the owner. Credits must be topped up, or the agent can wait for the next discount to be credited, which happens after a finished epoch. Retrying immediately will fail the same way.

### Is there a machine-readable list of error codes?

Yes. `https://www.gatewayz.ai/yield/errors.json` lists every code with its HTTP status, when it happens and the remedy, and the same list is inside `/yield/offer.json` under `errors`.

## Sources

- [CIP-0008: Message Signing](https://cips.cardano.org/cip/CIP-0008), as of 2026-10-27
- [CIP-0030: Cardano dApp-Wallet Web Bridge](https://cips.cardano.org/cip/CIP-0030), as of 2026-10-27

## Related

- [A compute budget that refills itself](https://www.gatewayz.ai/yield/agents)
- [Quickstart: link a Cardano stake address with CIP-8](https://www.gatewayz.ai/yield/agents/quickstart)
- [Delegation API reference](https://www.gatewayz.ai/yield/agents/api)
- [Is delegating ADA to a stake pool safe?](https://www.gatewayz.ai/yield/security)

---

Discounts are a share of staking rewards Gatewayz actually received, can change at any time, and are not a guaranteed return. Not available to US or Canadian persons. Every participant must confirm they are not a US or Canadian person before linking a wallet. Not investment, legal or tax advice. Figures as of 2026-10-27.

Updated 2026-10-27. Canonical page: https://www.gatewayz.ai/yield/agents/errors
