# Errors

> The pay-kit Go error values returned at New() time, and how per-request payment failures become the 402 response.

`paykit.New` returns an `error` when the configuration is unsound, so misconfiguration fails at startup rather than at request time. Per-request payment failures are turned into the `402` response by the middleware — your handler only runs once a payment verifies. All error values are exported sentinels you can match with `errors.Is`.

## Error values

| Value                    | Meaning                                                                                           |
| ------------------------ | ------------------------------------------------------------------------------------------------- |
| `ErrInvalidConfig`       | The `Config` is unsound (missing network, bad operator, etc.).                                    |
| `ErrDemoSignerOnMainnet` | The demo signer was used on `solana_mainnet` — refused so real funds never route to a public key. |
| `ErrSchemeIncompatible`  | x402 was offered on a multi-recipient (fee-bearing) gate; fees need MPP.                          |
| `ErrSchemeNotSupported`  | A requested scheme has no registered adapter.                                                     |
| `ErrMixedCurrencies`     | A gate's fees and amount don't share one currency.                                                |
| `ErrPaymentRequired`     | No valid payment was present where one was required.                                              |
| `ErrInvalidProof`        | A submitted payment credential failed verification.                                               |
| `ErrChallengeExpired`    | A payment arrived against an expired 402 challenge.                                               |

```go
client, err := paykit.New(cfg)
if errors.Is(err, paykit.ErrDemoSignerOnMainnet) {
    // set Operator.Signer before going to mainnet
}
```

## Boot-time safety rails

`paykit.New` validates up front: a demo signer on `solana_mainnet` is rejected (`ErrDemoSignerOnMainnet`), and when MPP is accepted without a `ChallengeBindingSecret` the kit resolves one automatically. The `Network` field is required — it is the only `Config` field with no default.
