Event Envelope Wire Format¶
Reference: the serialized event envelope contract shared by every language implementation.
At a glance
- What — the standard wire format: one MsgPack map with descriptive string keys that any MsgPack-capable language (Java, Rust, Node.js, Python, Go, …) can encode and decode with its idiomatic tooling — no custom codec.
- Why it matters — it is the interoperability contract for Event over HTTP between different language runtimes, and the template for any future event-to-bytes transport.
- For developers integrating runtimes across languages, and implementers of new language ports. This page is self-contained: a new implementation needs nothing else.
Two serialized forms exist. The standard format on this page is the language-neutral
contract and the default for Event over HTTP. The compact format (single-character map
keys) is the classic same-language form that remains the default for toBytes() and the
Kafka service mesh; it is documented here only as far as detection requires.
The envelope¶
A serialized envelope is a single MsgPack map with string keys. No MsgPack extension types are used. The envelope is self-contained — no out-of-band metadata is needed to decode it.
Core fields¶
id¶
| Type | Required |
|---|---|
| str | always |
Unique event instance id — an opaque string (UUID recommended). Encoders always emit it.
to¶
| Type | Required |
|---|---|
| str | when set |
Target route name, e.g. hello.world.
from¶
| Type | Required |
|---|---|
| str | when set |
Sender route name, used for observability and reply semantics.
reply_to¶
| Type | Required |
|---|---|
| str | when set |
Route that should receive the response, when the sender expects one.
cid¶
| Type | Required |
|---|---|
| str | when set |
Business correlation id, preserved end-to-end.
trace_id¶
| Type | Required |
|---|---|
| str | when set |
Distributed trace id.
trace_path¶
| Type | Required |
|---|---|
| str | when set |
Trace path, e.g. GET /api/hello.
span_id¶
| Type | Required |
|---|---|
| str | when set |
The sender's span id, carried so the receiver knows its own parent span.
status¶
| Type | Required |
|---|---|
| int | when set (default 200) |
HTTP-style status code. A value ≥ 400 marks the event as an error.
headers¶
| Type | Required |
|---|---|
| map of str → str | always (may be empty) |
User-defined parameters. Encoders always emit this field — an empty map when there are no headers — so statically-typed decoders need no per-field default handling.
body¶
| Type | Required |
|---|---|
| any MsgPack value | when set |
The payload: a map, array, string, integer, float, boolean, binary (bin), or nil.
An absent body means nil.
exec_time¶
| Type | Required |
|---|---|
| float | when set |
Function execution time in milliseconds.
round_trip¶
| Type | Required |
|---|---|
| float | when set |
End-to-end response time in milliseconds.
Extension fields¶
Optional fields a receiver MAY use and MAY ignore. Implementations that do not produce them remain fully conformant.
tags¶
| Type | Required |
|---|---|
| map of str → str | optional |
Engine-managed metadata (e.g. optional, json, broadcast). Tags are never visible to a
user function - the engine consumes them at delivery. Two tag names are reserved with
cross-language semantics that a conforming implementation must honor:
rpc- marks an RPC request (value = timeout in ms). The serving engine suppresses the worker-side trace record for an RPC-served execution; the caller's round-trip record is the single record for that span.my_cid- carries the business correlation-id across touch points and Event-over-HTTP hops. Metadata is never transported as envelope headers; the receiving engine injects the read-onlymy_correlation_idkey into the function's input header copy from this tag at delivery.
annotations¶
| Type | Required |
|---|---|
| map of str → any | optional |
Trace annotations recorded by the sender.
stack¶
| Type | Required |
|---|---|
| str | optional |
Stack-trace text — the portable error detail. The portable error contract is
status (≥ 400) + body (error message) + optional stack.
obj_type¶
| Type | Required |
|---|---|
| str | optional |
Language-specific payload type hint (a PoJo class name for Java). Advisory only.
exception¶
| Type | Required |
|---|---|
| bin | optional |
A language-native serialized exception object (Java only today). Meaningful only to a
receiver of the same language — cross-language receivers MUST ignore it. Use stack for
portable diagnostics.
Encoding rules¶
- Map keys are strings — including all keys inside a map-valued
body. - Optional fields: encoders SHOULD omit unset fields; encoding nil is equally valid. Decoders MUST treat absent and nil identically.
- Unknown keys MUST be ignored by decoders (forward compatibility).
- Numbers: encoders use the smallest natural MsgPack width; decoders MUST accept any integer width for integer fields and float32 or float64 for float fields.
- Binary values use the MsgPack
binfamily; strings are UTF-8str. - Timestamps travel as ISO-8601 UTC strings with millisecond precision
(e.g.
2026-07-21T12:00:00.000Z) — never as MsgPack extension types. - No byte-identical guarantee: map ordering is unspecified. Conformance is semantic — decode, compare values.
- Nesting: a payload nested deeper than 64 maps and lists is refused as a decoding error, the envelope map
being level 1, so a
bodymay nest 63 levels. Decoders MUST refuse deeper nesting instead of recursing into it, and encoders SHOULD NOT produce it. - Hostile headers: the lengths of str, bin and ext values and the counts of arrays and maps are 32-bit
unsigned and are checked against the bytes that remain before anything is allocated or consumed. A header that
promises more than the input holds is refused at the header, as a decoding error, and so is the format byte
0xc1, which the specification never uses. Decoders MUST do the same. The shared vector filemsgpack-hostile-header-vectors.json, byte-identical in the Java and Rust repositories, pins the inputs both engines refuse and the controls both decode. - Empty input: an empty payload decodes as an empty map, so an empty byte array is an empty envelope and never a decoding error; the canonical package decoder refuses it, because a package is never empty. The Java engine is the reference implementation and the Rust engine follows it.
- Exactly one value: a payload holds exactly one MsgPack value. Bytes after the top-level container, well-formed
or not, are refused as a decoding error (
Unexpected bytes after the value at offset N), as the canonical package decoder has always done; a decoder MUST NOT read one value and ignore what follows it, since two different byte strings would then decode to the same value. The shared vector file pins an empty map followed by0xc1and by a well-formed nil, and both engines refuse them.
Format detection¶
The compact format's keys are all exactly one character; standard keys are all two or more. A decoder therefore detects the format from the first map key without any negotiation, version field, or content-type variant. The Java implementation accepts both formats on every decode path.
Selecting the outbound format (Java)¶
Outbound format is transport policy. For Event over HTTP:
event.over.http.format = standard | compactin application.properties — the application default (standardwhen unset).x-event-format: standard | compactin the optional headers ofpo.request(event, timeout, headers, endpoint, rpc)— a per-call override, also usable per target in theyaml.event.over.httpconfiguration'sheaderssection. The header is consumed by the client and never sent to the peer.- The
/api/eventservice mirrors the requester's format in its response, so callers need no response-side configuration.
Use compact as a fallback when the peer is an older Java runtime that does not yet
decode the standard format.
Conformance vectors¶
Golden vectors (MsgPack bytes as base64, with expected decoded values) are maintained at
system/platform-core/src/test/resources/envelope-vectors/vectors.json and shared with
the official Rust implementation. A new
implementation is conformant when it decodes every vector to the expected values and its
own encodings round-trip through another implementation.
See also¶
- Event over HTTP — the transport this contract serves
- Event Envelope Reference — the in-memory API
- Configuration Reference —
event.over.http.format