> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chargerdojo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> The status codes the API answers, the failures that actually happen in practice, and how to tell a target failure apart from an outage on our side.

## First, separate the two kinds of failure

Every problem you will hit falls on one side of a line:

* **The target failed.** Your partner's implementation broke a rule. This is always
  reported inside a finished run: a failed check or verdict with the recorded exchange
  and the rule attached. It never arrives as an HTTP error from our API.
* **We did not get an answer.** Your request to our API was rejected, rate limited, or
  our runner was unavailable. This arrives as an HTTP status and says nothing about your
  partner.

A CI script that conflates these will tell your partner they are broken when the truth
is that your script never got an answer. Keep the exit codes apart, as in the scripts in
[Run a suite](/guide/run-a-suite#gate-your-build-on-it) and
[Run a charging journey](/guide/run-a-charging-journey#put-it-in-ci).

## Status codes

| Status | Meaning                                                                                                                                                                 | What to do                                                                                                                                      |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | The request body or a parameter is invalid. The message names the field.                                                                                                | Fix the request.                                                                                                                                |
| `401`  | Missing, invalid or revoked API key.                                                                                                                                    | Check the `Authorization: Bearer $DOJO_KEY` header, and that the key has not been revoked in Settings.                                          |
| `402`  | Your plan does not cover this. The body says which: `capability` names a feature such as Direct Payment, `limit` names a ceiling you reached such as partner endpoints. | Read the body. Buy the plan it names, or free a slot.                                                                                           |
| `404`  | Not found, including resources that exist but belong to another owner.                                                                                                  | Check the id. A correct-looking id that answers 404 usually belongs to a different account.                                                     |
| `409`  | Conflict: a journey plan expired or its hash changed, an `Idempotency-Key` was reused with a different body, or a `recoveryVersion` is stale.                           | Re-read the current state and repeat the step: preview again, use a fresh key, or decide against the run's current `recoveryVersion`.           |
| `422`  | The request is well formed but cannot be processed as sent.                                                                                                             | Read the message; it names what to change.                                                                                                      |
| `429`  | A rate or quota ceiling. In-flight journey runs hold a slot each, and a run paused as `recovery_required` keeps holding its slot until you decide.                      | Honour the `Retry-After` header. Read your ceilings from `GET /api/v1/usage`.                                                                   |
| `500`  | Something broke on our side. Not a verdict about your partner and not something your request can fix.                                                                   | Retry; if it persists, send us the run id.                                                                                                      |
| `502`  | The credentials handshake reached the partner, but the exchange failed.                                                                                                 | Read the returned connection error, then check the partner URL, token and advertised credentials endpoints.                                     |
| `503`  | **Our runner is unavailable.** Nothing was admitted; nothing reached your partner.                                                                                      | This is our service status, never a verdict about the target. Try again later. A journey start retried with the same `Idempotency-Key` is safe. |

A `202` is not an error and not an outcome: the work was accepted and is still going.
Poll or wait for the result.

## Registration

### The address my partner gave me does not work in the box you gave me

The most common shape of this is a segment: they sent you their versions URL, and the field wants
the URL that hangs off it. Paste `https://partner.example.com/ocpi/versions` into `partnerBaseUrl`
and the first request goes to `https://partner.example.com/ocpi/versions/versions`, which nothing
advertised, so what you read back is a 404 or whatever their server does with an unknown path.

Two things to do about it, in order. On the Endpoints page the line under the address names the
exact URL the next press will ask for, so read that before you press anything. If you are still not
sure, press **Check this address**: we send one authenticated `GET` to each likely candidate on the
host you typed, report what every one of them answered, and offer the one that served a version
list. Nothing is applied until you press **Use this address**.

The spec is why this cannot be guessed for you: "the exact URLs of the endpoints can be defined by
each party", and the example URLs in it "are descriptive only". Neither we nor anyone else can
derive a partner's base URL from their versions URL with certainty, which is why the check reports
what answered rather than deciding.

### Why does everything return 401 after a successful registration?

The partner is almost certainly still presenting the registration token (Token A). It was
valid until the handshake completed, and then it died. After registration each side
authenticates with the token the other side generated during the exchange.

### Why can the partner not push anything to us after registering?

They probably never fetched your endpoints. A credentials `POST` obliges the server to go
and read the client's endpoints for that version. Skipping it registers fine and then
fails days later, disguised as "your callbacks are broken".

### Why does the first authenticated request fail with an error that makes no sense?

Check the version on the connection. OCPI 2.1.1 sends the credentials token raw; from 2.2
onwards it is Base64 encoded. A version mismatch fails at the auth layer and looks
nothing like a version problem.

### Why does a connection that worked yesterday now fail every request?

Check whether the host moved, especially when nothing on your partner's side changed. A
tunnel handing out a new URL on restart is the usual cause, and a partner changing
infrastructure is the other one. The connection is still good: everything but the address
is unchanged, so
[change the address](/guide/connect-a-partner#when-their-address-changes) rather than deleting the
connection and registering again. Update credentials will not help, because it sends to the address
we already hold.

### Why does a second registration attempt succeed?

A second registration that succeeds is your partner's bug, not yours. The spec requires
`405 Method Not Allowed` for a `POST` from an already-registered client. Registration is
not idempotent, and a server that quietly re-registers is masking a state-machine bug
somewhere.

## Conformance runs

### Why does the run refuse a module?

The selected OCPI version does not advertise that module. That is not a gap in your
setup: a module with no proven suite on that version is not advertised, because a run
that reports failures you cannot act on is worse than one that says the module is not
covered. See [Run a suite](/guide/run-a-suite).

### Why does a scenario fail on a late step when the endpoint looks healthy?

Scenarios chain their own output: each step feeds the next. A red step 6 with a healthy
endpoint usually means something upstream returned nothing usable. Read the exchange on
the **first** red step, not the last.

### Why does my build fail when every failure is a warning?

Your build is gated wrongly. Gate on `failed`, not on warnings. A warning means a
recommendation was declined, and declining a recommendation breaks no rule. See
[Read your report](/guide/read-your-report).

## Charging journeys

### The run says `recovering`. Do I need to do anything?

No, the run needs nothing from you. Our runner is resuming from its checkpoint after a
restart on our side. No request is repeated, and the run continues on its own.

### What do I do when the run says `recovery_required`?

The delivery of one mutating action is uncertain and the tester will not resend it
automatically, because a replayed mutation could duplicate a session or a CDR on your
partner's side. The run is paused for your decision. Read the run, look at the
server-offered `recoveryOptions`, and apply one with the current `recoveryVersion`. A
stale version answers `409`: re-read and decide again. See
[Run a charging journey](/guide/run-a-charging-journey#when-a-run-pauses-for-a-recovery-decision).

### `runIntegrity` is `degraded` or `invalid`. Did my partner fail?

No. Run integrity describes how complete **our** evidence is, never your partner's
conduct. Target failures appear as failed verdicts with the exchange attached. A degraded
run means part of the story is unobservable, usually because a recovery decision chose to
continue without replay.

### Why did the journey start return `503`?

Our journey runner is unavailable. Nothing was admitted and nothing reached your partner.
Start again later; with the same `Idempotency-Key`, the retry either returns the original
run or admits it fresh, never both.

## Verdicts

### The report says "Compliant" but there are warnings. Am I compliant?

Yes. Nothing failed. A partner who ignores a `SHOULD` has broken nothing, and we will not
send you to fix code that already works.

### A check passed. How do I know it can even fail?

Because we broke our own server on purpose and watched that check go red. Every
conformance check on 2.1.1, 2.2, 2.2.1 and 2.3.0 has been proven capable of failing, and
that is enforced in our build, and the scenario suites have their own sweep with a
stricter gate. The reasoning, and the limits of the claim, are in
[Read your report](/guide/read-your-report).

## Still stuck

Every check carries the request that was sent and the response that came back. Open the
failing check and read the exchange before assuming the verdict is wrong. If the exchange
shows the tester doing something the specification does not permit, that is our bug, and
we want to know: [sales@chargerdojo.com](mailto:sales@chargerdojo.com).
