# Receipts and reason codes

> Every command's receipt carries a status code and a reason code. They're how bots and agents correct themselves, turning “why didn't it work?” into a machine-readable number.

Source: https://war3ai.com/en/docs/reason-codes/

```python
r = g.train(barracks, "hfoo")
bool(r)        # False
r.status       # 1              -> rejected
r.verdict      # 3              -> not enough food
r.reason       # 'rejected（人口不够）'  (SDK output: "rejected (not enough food)")
r.exec_us      # microseconds this command took on the game thread
```

`if r:` is equivalent to `r.status == 0` (the engine accepted it).

## Status codes: `status`

| Code | Name | Meaning | Common causes |
|---|---|---|---|
| 0 | `accepted` | The engine accepted it | — (but accepted ≠ done; see below) |
| 1 | `rejected` | Rejected by the engine | See `verdict` |
| 2 | `bad_unit` | The unit doesn't exist or its handle doesn't match | The unit is already dead; you used a stale unit object |
| 3 | `not_owner` | Not your unit | Commanding someone else's unit as a `player` |
| 4 | `fault` | Exception during execution (caught by the runtime; it won't take down the game) | Please report it with steps to reproduce |
| 5 | `bad_args` | Bad arguments | Wrong coordinates, slot index or four-character code |
| 6 | `unsupported` | Not supported | This runtime version doesn't have that capability |
| 7 | `bad_target` | Invalid target | The target is gone; wrong target type |
| 8 | `forbidden` | Not allowed for the lane's role | Issuing commands as an `observer` |
| 97 | `cancelled` | An exception was raised inside a batch block, so nothing in the batch was sent | Code inside a `with g.batch():` block raised an error |
| 98 | `held` | The unit is held by a higher-priority layer, so the command wasn't sent | The reference brain's reflex layer or a manual command from the console is holding the unit |
| 99 | `timeout` | Timed out | The deadline passed while the game was paused or lagging (expired commands are never executed) |

## Reason codes: `verdict`

When a command is rejected, the runtime explains why using the engine's own feasibility check. You can also ask before issuing the command: `g.can_do(unit, code)` returns the same codes.

| Code | Meaning | What to do |
|---|---|---|
| 0 / 220 | OK | — |
| 3 | Not enough food | Build food structures; watch `g.production(b).blocked` to catch it early |
| 8 | Not enough gold | Wait for gold; check `g.can_afford(code)` before issuing |
| 9 | Not enough lumber | Put more workers on lumber |
| 32 | Training queue full (7 slots) | Queue only 1 at a time: queue the next when `g.queue(b)` is empty |
| 183 | Missing prerequisite tech / building | Build the prerequisite first, or tier up |
| 185 | Building is busy | The altar is reviving a hero; the town hall can't upgrade while its queue isn't empty |
| 221 | Not available / under construction / upgrading / already exists | The hero already exists (use `revive` if it's dead); this shop doesn't sell that |
| 89 | Shop not stocked yet | At game start, items become available at the stock time in the item table; a newly built shop starts counting from the moment it's finished |
| 1001 | Target not visible | The target is in fog of war or the black mask; `attack_move` to its position |

## Accepted ≠ done

A receipt only tells you that the engine accepted the command, and it's read back in the same frame. It can't account for what happens afterward:

| Command | Can still fail after being accepted | How to confirm |
|---|---|---|
| Build | A spot in a forest is accepted immediately too; it fails when the worker gets there | Use `build_near` (it tracks whether the foundation appears), or wait for `production.done` |
| Cast | Interrupted, out of mana | On the next tick, check whether `g.cooldown(u, ability)` has started |
| Train | Queued, but never starts because there's not enough food | `g.production(b).blocked` |
| Move / attack | Overridden by other logic (or a higher-priority layer) | `g.current_target(u)`, `g.order_of(u)` |

## Query APIs

These APIs don't issue orders; they only ask the engine. The result is also placed in the receipt's `value` (the SDK returns the value directly):

| API | Returns |
|---|---|
| `g.can_do(u, code)` / `g.can_do_many([(u, code), ...])` | The reason codes in the table above |
| `g.tech(code, player=None)` / `g.tech_many([...])` | Research level / number of completed buildings (upgrade chain included) |
| `g.visible(x, y)` | Whether this point is visible to us |
| `g.gold_left(mine)` | How much gold is left in a mine |
| `g.enemy_ai_plan(enemy_unit)` | Where the computer opponent's captain plans to lead its troops (computer AI only) |
