Error code documentation registry#348
Conversation
- 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>
|
Here's a docs PR built on top of this which renders these error Markdown files within the docs site: |
m-hulbert
left a comment
There was a problem hiding this comment.
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.
| @@ -0,0 +1,6 @@ | |||
| --- | |||
| code: 93002 | |||
| identifier: mutable_messages_not_enabled | |||
There was a problem hiding this comment.
I'd prefer not to have 'mutable messages' exposed externally at all if possible.
There was a problem hiding this comment.
Ok, updated to message_updates_not_enabled in 1abd681.
| 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. |
There was a problem hiding this comment.
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."
|
|
||
| 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: |
There was a problem hiding this comment.
Very minor, but we'd code style untilAttach in docs.
| 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. |
There was a problem hiding this comment.
This would read better as shorter sentences rather than all the hyphens and commas.
- 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
left a comment
There was a problem hiding this comment.
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
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 aterrors/codes/<code>.mdwithcode,identifier,titleandsummaryfrontmatter, plus an optional Markdown body for detail-page content.Examples:
protocol/errors.jsonis 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 inerrors.jsonand seeded from the curated entries authored in the realtime repo.code,identifier,titleandsummaryare required; the body is optional.identifier— a stable, uniquesnake_casename 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.errors/scripts/validate-errors.js): filename ↔code, required fields,identifierformat and uniqueness, and title/summary length warnings.protocol/errors.jsonis 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.errors/README.md,errors/guidelines.mdanderrors/CLAUDE.mddescribe the registry and how to add and write entries.errors.json structure change (breaking for parsers)
protocol/errors.jsonchanges from a flatcode → titlemap 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:
identifierfor constant names.identifier.code → title.🤖 Generated with Claude Code