Skip to content

Error code documentation registry#348

Open
lmars wants to merge 9 commits into
mainfrom
error-docs
Open

Error code documentation registry#348
lmars wants to merge 9 commits into
mainfrom
error-docs

Conversation

@lmars

@lmars lmars commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

Introduces a single registry for Ably error codes under errors/ and makes it the source of truth. Each valid code is a Markdown file at errors/codes/<code>.md with code, identifier, title and summary frontmatter, plus an optional Markdown body for detail-page content.

Examples:

protocol/errors.json is now generated from this registry, so the set of codes and their descriptions can no longer drift between the two (a drift we hit and fixed in this branch — 40115).

This is the ably-common groundwork for rendering error documentation in the docs site and giving SDKs a single place to source error codes and their names.

Note to reviewers

This adds a Markdown file for every error code from the existing errors.json file that have either already been reviewed in the realtime repo (e.g. see https://github.com/ably/realtime/pull/8461, https://github.com/ably/realtime/pull/8479, and https://github.com/ably/realtime/pull/8512), or that I've had Claude generate and personally reviewed.

Feel free to review those individual Markdown files, but the thing I'm really interested in is the new registry structure:

If you do leave comments on the wording of the individual errors, please leave those with an approval and I will create tickets to address those separately.

What's in here

  • errors/codes/*.md — the registry. One file per code (254 in total), covering everything in errors.json and seeded from the curated entries authored in the realtime repo. code, identifier, title and summary are required; the body is optional.
  • identifier — a stable, unique snake_case name per code (e.g. token_expired), the canonical basis for the constant each SDK generates. Chosen deliberately rather than derived from the title, so it's a frozen contract that doesn't churn when copy is reworded. Seeded from existing SDK/server constants where they existed, then normalised.
  • US spelling across all entries, per the documentation style guide.
  • Validation in CI (errors/scripts/validate-errors.js): filename ↔ code, required fields, identifier format and uniqueness, and title/summary length warnings.
  • protocol/errors.json is generated from the registry (errors/scripts/generate-errors-json.js, npm run generate:errors), with a JSON schema and a drift guard — CI regenerates it and fails if the committed file is out of date, so it can't be hand-edited out of sync.
  • Docs: errors/README.md, errors/guidelines.md and errors/CLAUDE.md describe the registry and how to add and write entries.

errors.json structure change (breaking for parsers)

protocol/errors.json changes from a flat code → title map to a keyed object carrying the new fields:

{
  "codes": {
    "40142": { "identifier": "token_expired", "title": "Token expired", "summary": "" }
  }
}

Consumers that only link to the file are unaffected. Consumers that parse it need updating — as follow-ups in their own repos:

  • ably-go / ably-ruby — update their error-code generators to read the new shape and adopt identifier for constant names.
  • ably-ai-transport-js — move from a runtime key-lookup to generating its enum from identifier.
  • top-error-codes dashboard (ours) — reads code → title.

🤖 Generated with Claude Code

lmars and others added 8 commits July 3, 2026 03:06
- 40165, 40166: previously curated but missing from the code → title map.
- 103008 (Push transport credentials invalid): reserved for the push
  transport credential-rejection case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Establish errors/codes/ as the source of truth for which error codes are
valid and what they mean: one Markdown file per code, with YAML frontmatter
(code, title, summary) and an optional Markdown body for the detail page.

Every code has a title and summary; many also carry a body. README, CLAUDE
and guidelines describe the registry and how to write entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add errors/scripts/validate-errors.js: checks every codes/<code>.md has a
matching filename/code, required code/title/summary fields, and that every
errors.json code has a registry file (completeness). Wire it into the check
workflow via the validate:errors npm script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an `identifier` frontmatter field to each codes/<code>.md: a stable,
unique snake_case name that is the canonical basis for the constant each SDK
generates for the code. Unlike the title (prose that may be reworded), the
identifier is a frozen contract, so SDKs can generate consistent constants
from the registry rather than deriving churny names from description text.

Seeded from existing SDK/server constants (ably-go, then realtime-go),
falling back to the title, then normalised — abbreviations expanded, UK
spelling, named after the cause rather than the consequence.

The validator now requires `identifier`, checks it matches ^[a-z][a-z0-9_]*$,
and rejects duplicates. README, guidelines and CLAUDE document the field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Ably documentation style guide requires US spelling. Convert the UK
spellings present in the code entries (behaviour, cancelled, favour,
recognised, signalled, synchronised, unauthorised, unrecognised and their
inflections) to US across titles, summaries, bodies, and identifiers, and
update guidelines/CLAUDE to require US spelling.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sync two codes split out in the realtime repo:
- 40128 (account application limit exceeded), split from 40115.
- 40151 (token connection limit exceeded), split from 80019.

40115's meaning moved to 40128, so correct 40115 in errors.json to its
current "account restricted (request limit exceeded)" meaning (the registry
entry already reflected this). Both new codes get an identifier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Make errors/codes/*.md the single source of truth and derive errors.json
from it, eliminating the drift between the two (e.g. the 40115 wording that
had gone stale in errors.json). errors.json changes shape from a flat
code → title map to `{ codes: { "<code>": { identifier, title, summary } } }`,
now carrying the identifier and summary, not just a title.

- errors/scripts/generate-errors-json.js writes errors.json from the registry
  (shared frontmatter parser with the validator so they can't diverge).
- json-schemas/src/errors.json describes the new shape; validate:errors-json
  checks it.
- CI regenerates and `git diff --exit-code`s errors.json as a drift guard, so
  it can't be hand-edited out of sync.
- The validator drops its now-redundant errors.json cross-check.

This changes the structure parsed by ably-go, ably-ruby and
ably-ai-transport-js; their generators need updating to read the new shape
and adopt `identifier` (a follow-up, per the error-docs plan).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hand-maintained ranges table had drifted from reality and duplicated
information now carried per-code in the error registry. Drop it rather than
keep a second, stale source.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lmars

lmars commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Here's a docs PR built on top of this which renders these error Markdown files within the docs site:

ably/docs#3458

@m-hulbert m-hulbert left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a read through all the related docs and overall looks good to me.

I didn't read through every error description, but scanned through them all, and dropped a few comments. Most are very minor and non-blocking - with one exception on the identifier for a specific error.

My only pushback would be that I think we should mandate a body being added for new errors going forwards, rather than making it optional. Otherwise all the work you'll be putting in to backfill them will need to be repeated at some point.

Comment thread errors/codes/93002.md Outdated
@@ -0,0 +1,6 @@
---
code: 93002
identifier: mutable_messages_not_enabled

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer not to have 'mutable messages' exposed externally at all if possible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, updated to message_updates_not_enabled in 1abd681.

Comment thread errors/codes/93002.md Outdated
code: 93002
identifier: mutable_messages_not_enabled
title: Message annotations, updates, appends, and deletes not enabled
summary: An operation could not be performed because it requires a feature that is enabled by the channel namespace's 'Message annotations, updates, appends, and deletes' setting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a mouthful with "the channel namespace's..."

Can we not go with something like "An operation could not be performed because the channel did not have the 'Message annotations, updates appends, and deletes' rule enabled."

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied your suggestion in 1abd681.

Comment thread errors/codes/90008.md Outdated

Without persistence, there is nothing to do and the error can be ignored. The client already has all recent messages, because it has received everything since its attach point and that point is older than the recent window. The older history [untilAttach](https://ably.com/docs/storage-history/history) would have returned is not retained, so there is nothing more to recover.

With persistence, the older history untilAttach would have returned is retained, and can be fetched with a plain [history](https://ably.com/docs/storage-history/history) request without untilAttach. That response won't line up exactly with the messages the client already received from the channel, so choose how to reconcile them:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor, but we'd code style untilAttach in docs.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backtickified in 1abd681.

Comment thread errors/codes/80016.md Outdated
code: 80016
identifier: connection_replaced_by_a_newer_one
title: Connection replaced by a newer one
summary: An operation was attempted on a connection that was no longer current — a newer connection had replaced it, or its transport handle had been recycled — so the operation could not be applied and the client re-establishes to continue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would read better as shorter sentences rather than all the hyphens and commas.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeh, updated in 1abd681.

- 93002: rename identifier to message_updates_not_enabled (avoid exposing
  "mutable messages") and reword the summary to reference the channel rule.
- 80016: rewrite the summary as shorter sentences.
- 90008, 40024: code-style `untilAttach` in the body text.

Regenerate protocol/errors.json to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@umair-ably umair-ably left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only focused on the guidelines and a single md example, but this is great!

Big fan of how the body has been structured too. Just wanted to call out we've still got "What you should do" instead of "remediation". I think this is fine and better suits the content and writing style here. Just highlighting that ably-js will have a remediation property as previously discussed but this diversion between the two is fine imo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants