Skip to content

Available now

Handle the bus's answers ​

A bus will refuse some of your messages and will sometimes be unavailable. What your product does next decides whether a newsroom loses data. This page makes that behaviour explicit.

One shape for every answer ​

json
{ "accepted": true,  "message_id": "…", "message_type": "story.context", "family": "story-context", "tolerated": [ … ] }
{ "accepted": true,  "duplicate": true, "message_id": "…" }
{ "accepted": false, "violations": [ { "source": "…", "rule": "…", "message": "…", "path": "/json/pointer" } ] }

Authentication failures, rate limits and the firewall use the refusal shape too. The exceptions come from AWS in front of the bus, with a body of the form {"message":"…"}: on the routes signed with an AWS role (/v1/tenants/{t}/iam/…), 403 for a request that is unsigned, badly signed or signed with expired credentials; and 403 Missing Authentication Token for a path the API doesn't have.

Reading a refusal ​

json
{"accepted":false,"violations":[
  {"source":"schema","rule":"envelope.format.uuid","path":"/message_id","message":"must be a valid uuid"},
  {"source":"schema","rule":"story-context.required","path":"/payload","message":"must have required property 'story_id'"}
]}
FieldWhat it tells you
HTTP statusThe class of problem, and whether a retry can help (below)
sourceWho says no: schema and conformance are SOM 1.0; sequence is SOM's snapshot-order rules, checked against the story's previous snapshot; policy is this bus's own rules. See Verdicts and refusals
ruleA stable id. Branch on it, never on message. Each has a page in the rule catalogue with how to fix it
pathA JSON Pointer into your message, where the bus can say where
messageFor people. It may change: don't parse it

A message stops at the first stage that refuses it, but within SOM validation the bus reports every violation, not just the first. Don't assert on the number of violations: assert on the rule you expect.

Schema rules are named <schema>.<keyword>: the schema that failed (envelope, or the payload's family) and the JSON Schema keyword. envelope.format.uuid is a malformed id in the envelope; story-context.required is a missing member of a snapshot.

What to do with each answer ​

StatusMeaningRetry?Your product should
202Accepted and published for delivery–Carry on. Log anything under tolerated: warnings, not failures
200 + duplicateYou already sent exactly this message, and it was published–Treat it as success. This is what makes retries safe
400Not valid SOM, or not JSONNoA bug in your product. Log rule and path, alert, don't resend it unchanged
401Token missing, invalid or expired, or issued before a secret rotationOnce, with a new tokenRefresh and retry once. If it fails again, it's configuration: stop and alert. (AWS signing failures are 403: refresh your AWS credentials)
403Connection not active, the wrong workspace, an AWS role not yet verified, or a system_id or message type outside your grantsNoConfiguration. Alert
403 request.blockedRefused by the bus's firewallNoCheck what your client sends; ask RND if it's a normal message
409 on a sequence ruleThis snapshot would break the storyNot this messageYour story state is behind or wrong. Rebuild a complete snapshot from current state, with the next sequence_number and a new message_id. A terminal story stays terminal: tell the user
409 commit.contentionAnother writer changed the story at the same momentWith a fresh snapshotAs above. If it keeps happening, two processes are writing one story
409 story.not_ownerYour system doesn't own this story, and your workspace refuses such snapshotsNoPublish from the story's owner, or ask a workspace admin for a hand-off. The same rule under tolerated (the default) is a warning: the snapshot was accepted
409 message_id.reusedThis message_id was used for a different messageNoA bug: every new message needs a new message_id
409 message.supersededA retried snapshot was recorded but never published, and its story has accepted a newer snapshot since. It is not deliveredNoNothing: the newer snapshot supersedes it. If the story needs a change, send a new snapshot from current state with a new message_id
413Over 240,000 bytesNoYou're sending content, not references. Move media and long text out
429 rate.limited or quota.exceededOver a rate limit, or your connection's daily allowanceYes, with backoffRetry the same message later, honouring Retry-After when present. Limits
503bus.publish_failed or registry.unavailable: not publishedYes, with backoffRetry with the same message_id and body
503 message.in_flightAn earlier attempt of this message was recorded less than 30 seconds ago and isn't confirmed published yet. Nothing new was acceptedYes, with backoffRetry with the same message_id and body, for at least 30 seconds. See Retries
Timeout, network error, other 5xxUnknown whether it arrivedYes, with backoffRetry the same message_id and body. If it did arrive, you get 200 duplicate

How to retry: Retries and idempotency.

Show it to people ​

Newsroom users shouldn't see "409". Decide what your UI or logs say for each class:

ClassA user-facing meaning
400"This story couldn't be shared with other systems: [field] is invalid." Point at path
403"This system isn't allowed to publish that." For an administrator
409 stale or terminal"Someone else changed this story", or "This story was killed and can't be reopened"
503, retries exhausted"Other systems haven't received the latest version yet. Retrying."

Checkpoint ​

  • [ ] My client branches on status and rule, never on the message text.
  • [ ] After a 409 on a snapshot it rebuilds from current state and never resends the refused message.
  • [ ] 400, 403 and 413 alert and don't retry.

Next: Retries and idempotency.

SOM is an open standard maintained by the SOM working group. This service is not endorsed by it.