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

# canonical_bytes

> The canonical form of an arbitrary mapping: UTF-8 JSON, sorted keys, no whitespace.

`ctrlrun.canonical_bytes` — function, defined at `src/ctrlrun/action.py:201`

```python theme={null}
def canonical_bytes(payload: Mapping[str, Any]) -> bytes
```

The canonical form of an arbitrary mapping: UTF-8 JSON, sorted keys, no whitespace.

**This is the encoding half of `v0.1 §2.3`, promoted rather than written** (SPEC-v0.6 §6.2,
§9.1). `canonicalize(action)` builds a fixed six-key payload and calls this, so there is
provably one implementation rather than two that agree today: the receipt chain (§6.2) and
the policy hash (§7.1) both need the canonical form of a *document*, and the alternative was
a private second canonicalizer, which §6.2 forbids by name.

Sorted keys recursively, `separators=(",", ":")`, `ensure_ascii=False`, UTF-8, and **`float`
rejected at any depth**. The rejection is not `json.dumps`'s doing -- `allow_nan=False` only
catches `NaN` and the infinities -- so it is checked here, because a canonicalizer that
silently encoded `0.1` would make two hosts with different libm disagree about a hash.

`ctrlrun.action/v1` is unchanged by this promotion and T164b is the corpus that proves it.

## Next

* [Python API index](/reference/api/index).
* [Get started](/get-started/quickstart) · [Why](/why).


## Related topics

- [canonicalize](/reference/api/canonicalize.md)
- [Python API](/reference/api/index.md)
- [Action and hash](/concepts/action-and-hash.md)
- [Receipts and evidence](/concepts/receipts-and-evidence.md)
- [Approvals in Slack via webhook](/cookbook/slack-approvals.md)
