Errors¶
Every refusal is a distinct sentinel, created with
errors.NewSentinel, so it survives a process boundary and can
be counted by kind rather than as "parse failed". Match with errors.Is.
Codec¶
ErrMissingAttribute¶
One of the four required attributes — id, source, specversion, type — is absent or empty.
Returned by both Marshal and Unmarshal, so a producer learns in its own process that it would
emit something no consumer accepts.
Also returned for an extension present with an empty value. An extension is caller-defined, so
present-with-nothing is a state the caller chose and one Marshal cannot represent — an empty value
writes no header, and the extension would vanish in transit with no error.
ErrUnsupportedSpecVersion¶
specversion is present and is not 1.0. An absent specversion is ErrMissingAttribute, and
the distinction is load bearing: "this is not a CloudEvent at all" and "this is a CloudEvent from a
version we do not implement" are different problems, and an operator alerting on version skew wants
only the second.
This is the refusal the rest of the strictness follows from: specversion tells a reader how to
interpret every other attribute, so continuing past an unrecognised one is guessing at the shape of
what is held rather than being lenient about it.
If you see this in production, something is emitting a CloudEvents 0.3 event.
ErrInvalidTime¶
ce-time is present and is not an RFC 3339 timestamp. Absent is fine; unparseable is not.
ErrDataSchemaNotAbsolute¶
dataschema is present and is not an absolute URI. The specification types it as URI rather than
URI-reference, so unlike source there is no base to resolve a relative one against, and a
consumer receiving one could not tell which schema was meant.
ErrInvalidExtensionName¶
An extension name breaks the specification's naming MUSTs. See Add an extension attribute for the grammar, and note that the SHOULDs are deliberately not enforced.
ErrReservedExtensionName¶
An extension is named after one of the eight specification attributes — id, source,
specversion, type, datacontenttype, dataschema, subject, time.
Separate from ErrInvalidExtensionName because the answer is different: the name is well formed,
it is just already taken. Without the refusal, Extensions["id"] would overwrite ce-id on the way
out and the event would marshal with a hijacked identity, no error, and a round trip that agrees
with itself.
ErrControlCharacter¶
An attribute value contains a character the specification's String type disallows — U+0000–U+001F
or U+007F–U+009F.
Percent-encoding would carry them, which is precisely why they are refused instead. net/http
rewrites a newline in a header rather than refusing it, so without the check a receiver would get a
different attribute value than the sender set, with nothing erroring anywhere.
ErrInvalidEncoding¶
A header value is not validly percent-encoded: a truncated escape, a non-hexadecimal one, or a value that decodes to invalid UTF-8.
Both bindings require exactly one round of decoding on receive, so a malformed escape means the sender and this reader disagree about where the value ends. Decoding it leniently would produce a different string than the sender wrote, silently.
ErrAmbiguousHeader¶
One attribute arrived twice with different values — as two spellings that fold to the same key, or as two values under one key.
Only headers this codec owns are considered. X-Forwarded-For with two hops is the ordinary shape
behind a proxy and is none of the codec's business.
Like every other refusal, this one returns the partial event: the ambiguous attribute is untrustworthy, everything else that was readable is not.
URN¶
Listed in the URN grammar reference alongside the rules they enforce.
What Unmarshal returns alongside an error¶
Every refusal returns the partially-assembled Event, carrying whatever was readable, including
its extensions. Log e.ID and e.Source rather than "a message failed to parse" — see
Handle a refused event for why that matters more than it
looks.