# Errors

When the Magistrate module throws, no decision was made. Treat every error as NO in your app, and your backend gets no receipt to accept.

A `deny` is not an error. It comes back as a `DecisionResult`.

## Module errors

Swift throws `PolicyError`. Kotlin throws a subclass of `PolicyException` with the same name in upper camel case, for example `PolicyException.NoProofProduced`.

| Swift case | What happened | What to do |
|---|---|---|
| `notProvisioned` | No policy is connected to your license yet | Ask your Octet contact to connect your published policy. See [Write a Policy](/docs/magistrate/get-started/write-a-policy/#6-connect-the-policy-to-your-license) |
| `licenseIdUnavailable` | The SDK hasn't activated its license yet | Wait for `Octet.start` to finish, then retry |
| `bundleFetchFailed(_)` | The policy couldn't be downloaded | Check the network and retry |
| `bundleRejected(.badSignature)` | The policy isn't signed by Octet | Don't retry. Write to developer@octetproof.com |
| `bundleRejected(.malformed)` | The policy couldn't be read | Don't retry. Write to developer@octetproof.com |
| `bundleRejected(.stale)` | The policy is older than one this device already used | Retry. A cache may be serving an old version |
| `bundleRejected(.unsupportedPlan)` | The policy needs a newer Magistrate module | Update the module |
| `unsupportedRegion(canonical:)` | The policy names a region this module can't prove yet | Update the module |
| `malformedTrustRoot(kid:)` | A key on your license that verifies policies is malformed | Write to developer@octetproof.com |
| `noProofProduced(details:)` | The SDK couldn't make any proof the policy needs | Retry after a few seconds. `details` says why for each region |
| `bindingUnavailable` | The policy has a `disc`, and this SDK version can't prove one yet | Use a policy without discs until an SDK release supports them |
| `invalidPolicySet(count:)` | `decideMany` got no policies, or more than 16 | Pass 1 to 16 policy names |
| `decideRejected(_, detail:)` | The engine refused the request. See below | Depends on the reason |
| `decideFailed(_)` | The request to the engine failed for another reason | Check the network and retry |

The `String` values in `bundleFetchFailed`, `decideRejected` and `decideFailed` are diagnostics for your logs. Don't branch on them.

### decideRejected reasons

| Reason | HTTP | What happened |
|---|---|---|
| `badRequest` | 400 | The engine couldn't read the request |
| `challengeUnknownOrExpired` | 401 | The challenge expired before the proofs arrived. Retry |
| `challengeReused` | 409 | The challenge was already used. With `decideMany`, also when a policy got a new version during the check. Retry |
| `policyScopeMismatch` | 422 | The challenge was issued for another policy |

## Publishing errors

The studio shows these when it publishes a policy. The engine refuses the policy and nothing changes for your apps.

| HTTP | Message | What to do |
|---|---|---|
| 400 | `the OPL doesn't parse: parse error at <line>:<column>: ...` | Fix the policy text at that position. A disc with an out-of-range latitude, longitude or radius is a parse error too |
| 400 | `the OPL doesn't parse: check error: ...` | A name is defined twice or used without being defined. Fix the name |
| 422 | `policy can't be published: unknown country code "XX"` | The code isn't an ISO 3166 country. Check the code |
| 422 | `policy can't be published: unknown subdivision code "US-ZZ"` | The code isn't an ISO 3166 subdivision. Check the code |
| 422 | `policy can't be published: country code "VA" has no map data in this engine` | The code is valid, but the engine has no boundary for it yet. The same message exists for subdivision codes. Write to developer@octetproof.com |
| 422 | `policy can't be published: city("...") isn't supported yet; use a disc around the city instead` | Use a `disc` around the city |
| 422 | ``policy can't be published: region `...` is not defined`` | The policy uses a region name it doesn't define. Fix the name |
