Skip to content

DOC-7253 Document client library exceptions on the error reference pages - #4449

Merged
andy-stark-redis merged 11 commits into
mainfrom
DOC-7253-client-exceptions-errors
Nov 4, 2026
Merged

andy-stark-redis merged 11 commits into
mainfrom
DOC-7253-client-exceptions-errors

Conversation

@andy-stark-redis

@andy-stark-redis andy-stark-redis commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Note: I'm wondering if the Lettuce and SE.Redis notes in the table would look better as footnotes under the table? Also, maybe the Possible Errors bit of the API Methods tab (command pages) needs neater styling?

DOC-7253

Documents the exception or error type that each client library raises for the errors on the common/ error pages, and surfaces them on the command pages.

What changed

  • data/client-exceptions.json: per client and error page, the class, message, optional check and note. Ten clients (redis-py, Jedis, node-redis, Lettuce, go-redis, ioredis, StackExchange.Redis, Predis, redis-rb, redis-rs), each reproduced live on redis:8.10.
  • "In client libraries" table on all 27 errors/common/ pages (error-clients shortcode, with a Markdown/JSON expansion for the AI-readable output). The lookup match lists gained the specific class names.
  • "Possible errors" block on the API methods tab, derived from the command lists in data/errors.json and the client mapping. No change to the 527 mapping files. Commands with no linked page show nothing.
  • build/errors/: live_clients.py and bridges/ run the live checks through each client; client_baselines/ holds the results. update_errors.py check now fails when the data disagrees with the baselines, and /update-error-reference has a step to refresh them.

Review notes

  • The sandbox-free Hugo build passes, including /commands (the Markdown partial guards a nil .File).
  • Source-derived and unverified: redirect-following notes for the cluster clients, and the timing-dependent denied and max-clients rows. The StackExchange.Redis ASK row is omitted.
  • Not changed, but wrong: the Jedis hierarchy on content/develop/clients/jedis/error-handling.md (for example, JedisClusterException extends JedisDataException). Left for a separate decision.
  • The skill step in /update-error-reference hasn't been run on a real release yet.

🤖 Generated with Claude Code


Note

Low Risk
Changes are limited to docs-site build tooling, baselines, and maintainer workflows; no runtime product code paths.

Overview
Adds live_clients.py and a bridges/ layer so the same Docker-based live checks used for redis-py can run through Jedis, Lettuce (sync/async/reactive), node-redis, ioredis, go-redis, StackExchange.Redis, Predis, redis-rb, and redis-rs, recording each library’s exception class and message.

Each bridge installs the client, runs a small probe (OK/EXC protocol in _common.py), and maps live_checks calls to raw commands. live_checks.py now records results under a configurable CLIENT_KEY and merges EXTRA_META (client version) into run metadata. Committed client_baselines/*.json capture accepted runs against Redis 8.10.2; update_errors.py check (via check_clients) is wired to fail when data/client-exceptions.json disagrees with those baselines—build/test_update_errors.py adds coverage for diffing and validation.

build/errors/README.md and the update-error-reference skill gain a step 5 workflow: run bridges one at a time (shared ports), update client-exceptions.json, then --accept baselines. content/develop/clients/dotnet/error-handling.md links to the error reference for SE.Redis mapping.

Reviewed by Cursor Bugbot for commit 0c1aa16. Bugbot is set up for automated code reviews on this repo. Configure here.

andy-stark-redis and others added 7 commits November 3, 2026 14:02
…ages

Adds data/client-exceptions.json, an error-clients shortcode (with a Markdown/JSON expansion), and an "In client libraries" table on each of the 27 pages in errors/common. The table replaces the 15 hand-written "In redis-py, this error is" sentences. Specific class names also go into each page's match list so the lookup box finds a pasted exception name.

The data is keyed by page file name, not by server prefix or message. The pages already group the errors a reader sees, and the same prefix can map to different classes depending on the message (redis-py maps ERR variants one by one). Per-message data would be 1,783 rows of mostly the generic class.

Both clients were run live, with the same scenarios as build/errors/live_checks.py. redis-py comes from live_baseline.json (7.4.1). For Jedis 8.0.2 I copied live_checks.py and swapped the redis-py client for a small Java probe that runs each command through Jedis and prints the exception class and message. All 25 rows read from Protocol.processError matched the run. DENIED and max-clients, which I could not predict from source because the server closes the socket, are JedisConnectionException with "Unexpected end of stream." in Jedis. The probe and its harness are not in the repo yet.

The two clients differ in a way that matters for the tables. redis-py strips the prefix from mapped errors (ReadOnlyError says "You can't write..."), but leaves it on unmapped ones (ResponseError says "WRONGTYPE ..."). Jedis always keeps the full message and maps only MOVED, ASK, CLUSTERDOWN, BUSY, NOSCRIPT, NOAUTH, WRONGPASS, NOPERM and NOPROTO. In Jedis, CLUSTERDOWN is a JedisClusterException that extends JedisDataException, and redis-py MovedError extends AskError.

markdown-error-clients.html runs on every page that goes through process-markdown-content.html, including generated sections such as /commands that have no .File. Reading .File there broke the whole Hugo build, so it now looks for the shortcode first and guards .File.

Learned: redis-py and Jedis map server prefixes to classes very differently, so the table is per page and shows the message each client produces, not just the class
Constraint: layouts/partials/markdown-error-clients.html must not read .Page.File unless the page contains the shortcode, because generated pages have no File and the build fails
Directive: Add a client to data/client-exceptions.json by running it against the live_checks.py scenarios first, and add its id to "order"; do not write rows from the client's docs
Directive: Do not add the generic classes (ResponseError, JedisDataException, ConnectionError) to a page's match list, because they would match every pasted error
Gaps: The JedisCluster and RedisCluster notes on MOVED and ASK (they follow the redirect themselves) come from source, not from a live run
Gaps: Jedis was run against server 8.10.2 and redis-py against 8.10.3
Recheck: when a Jedis release changes Protocol.processError or the exception hierarchy
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ient bridge

live_clients.py runs the checks of live_checks.py with another client library, so each new client in the error reference needs a small bridge and probe, not another copy of the script. A bridge in bridges/ turns the redis-py calls that the checks make into raw commands for a probe program in the client's language, and the probe prints the exception class and message. The Jedis bridge is the first, and client_baselines/jedis.json holds its result.

live_checks.py gets two hooks (CLIENT_KEY and EXTRA_META) and nothing else, so live_baseline.json and the verify step behave as before. The existing tests still pass. Running the Jedis bridge through the new path gave exactly the replies of the earlier scratchpad run, which is how I checked that the move changed nothing.

Learned: the bridge replaces py_err and client in the live_checks module at run time, so scenario code stays client-neutral and a new client needs no change to it
Constraint: live_baseline.json must keep only redis-py names under redis_py, because compare() and verify --accept key off that
Directive: Put a new client's probe and bridge in bridges/ and run it through live_clients.py; do not copy live_checks.py
Gaps: The Jedis bridge needs Maven Central and a working mvn; ERRORS_CACHE controls where it builds
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…pages

Runs node-redis 6.3.1 through the live checks (bridges/node_redis.py and its probe, result in client_baselines/node_redis.json) and adds it to data/client-exceptions.json after redis-py and Jedis.

node-redis maps no prefix to a class. Every server error is a SimpleError that keeps the full message, and callers have to test err.message.startsWith. So its column is the same class on all 27 pages. That is accurate, and it is the point of the table: a reader who sees ReadOnlyError in redis-py and JedisAccessControlException in Jedis learns that node-redis has nothing to catch by class.

Two results differ from the server text. node-redis 6.3.1 sends HELLO when it connects, so NOAUTH surfaces from connect() with "NOAUTH HELLO must be called with the client already authenticated..." and not "NOAUTH Authentication required." Reading the page's example against that message would confuse a reader, so the row carries the real message and a note. And exec() rejects with the error of the command that failed to queue, not EXECABORT, like redis-py. Unlike Jedis, node-redis receives the DENIED and max-clients errors as replies, so they are SimpleError with the server text and not a connection error.

SimpleError, like the other generic classes, stays out of each page's match list.

Learned: the same server error can reach the reader as a prefix-specific class (redis-py, Jedis) or as one generic class with the prefix in the message (node-redis), and a client's connect handshake can change which error and message you see
Constraint: node-redis rows must stay tied to the version in data/client-exceptions.json, because the HELLO-on-connect behavior is version-dependent
Gaps: The createCluster redirect note (follows ASK and MOVED, throws MaxCommandRedirectionsError after 16 attempts) comes from cluster/index.js, not a live cluster client run
Recheck: when node-redis changes its default protocol or its handshake, or adds per-prefix error classes
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…mon error pages

Runs Lettuce 7.9.0.RELEASE (sync, async and reactive) and go-redis 9.22.0 through the live checks, with bridges and probes in build/errors/bridges and results in client_baselines. The table on each page now covers five clients. Its column is "Exception or error type", because go-redis has errors, not exceptions.

Lettuce is one entry. The three APIs raised the same exception class and message on all 27 pages once I ignored one artifact: the sync API adds a cause that is a copy of the exception it throws. The only difference is that the async API wraps the exception in an ExecutionException from get(), or a CompletionException from join(), so that goes in a note on the Lettuce client, not in three rows. Lettuce maps BUSY* to RedisBusyException by prefix, so BUSYKEY and BUSYGROUP are RedisBusyException too, though they are different errors. Lettuce also sends HELLO and authenticates while connecting, so NOAUTH, WRONGPASS, DENIED and max-clients come out of connect() as a RedisConnectionException ("Unable to connect to <host>/<unresolved>:<port>") whose cause is the server's error.

go-redis has typed errors, but they live in an internal package and callers cannot name them. They reach them with redis.IsMovedError(err) and the other helpers, or redis.HasErrorPrefix. So an entry may carry an optional check, shown as "Test with", and the type column shows the public redis.Error interface. node-redis, which also cannot tell errors apart by class, got the same: err.message.startsWith('PREFIX'), the idiom its own cluster code uses.

Where a client's class cannot identify the error, its name stays out of the lookup match list. Only RedisLoadingException, RedisNoScriptException and RedisReadOnlyException are added. RedisBusyException is left out because it covers three pages.

Learned: a client can be one library with three APIs and still be one table row, so check whether the exceptions differ before splitting it; the sync/async/reactive difference was wrapping, not class
Constraint: the DENIED and max-clients rows depend on whether a client reads the error before the server closes the socket, so they can change with timing, a proxy or the client version
Directive: Give a client a check only when its class cannot identify the error, and take the check from what the probe reported as true, not from the client's docs
Gaps: The RedisClusterClient (5 redirects) and go-redis ClusterClient (MaxRedirects, 3) notes come from source, not a live cluster client run
Gaps: go-redis HasErrorPrefix checks are from the source of error.go, not run per page
Recheck: when Lettuce or go-redis changes its error types, its HELLO handshake, or its redirect defaults
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…-rs to the client exceptions

Runs five more clients through the live checks (ioredis 5.11.1, StackExchange.Redis 3.0.0, Predis 3.5.1, redis-rb 6.0.0, redis-rs 1.6.0), each with a bridge and probe in build/errors/bridges and its result in client_baselines. The table on each common page now covers ten clients. StackExchange.Redis stands for NRedisStack too, because NRedisStack 1.6.0 depends on it. hiredis (a C library with no exceptions) and RedisVL (it wraps redis-py) are not covered.

The clients fall into three groups, and the table shows which. redis-py, Jedis, Lettuce, redis-rb and redis-rs turn some prefixes into their own classes (redis-rs has a real ErrorKind enum, and the rest are partial). ioredis, node-redis and Predis keep one class and expose the prefix through the message, or for Predis through getErrorType(), so those rows carry a check. go-redis uses helper functions. Predis was first wrong because of my probe, not the client: RawCommand takes the command name and the arguments separately.

Several rows are not what the server's text suggests. StackExchange.Redis raises RedisConnectionException, not a server exception, whenever the handshake fails, so NOAUTH, WRONGPASS, DENIED, max-clients, BUSY and NOPERM (for the restricted user in the check) come out of Connect. It refuses a write to a replica itself, and it follows MOVED so nothing reaches the caller. redis-rb and Lettuce send HELLO when they connect, so NOAUTH there names HELLO, as in node-redis. ioredis never raises LOADING by default, because its ready check waits for the load to finish (confirmed in Redis.js and live: with enableReadyCheck set to false it raises ReplyError). redis-rb, Predis and node-redis raise the error of the command that failed to queue and not EXECABORT, like redis-py, while redis-rs and ioredis do report it.

The ASK row is left out for StackExchange.Redis because the sync call raised a connection error about the hash slot and the async call raised nothing, in a deliberately half-migrated slot. I could not tell which a user would see.

Learned: how a client surfaces a server error depends as much on its connect handshake and its retry or ready-check behavior as on its error classes, so the same page can show a server error in one client and a connection error in another
Constraint: the ioredis loading row only holds with enableReadyCheck set to false; the default behavior is to wait
Directive: Keep ASK out of the StackExchange.Redis column unless it is re-checked on a real cluster rather than the half-migrated slot of live_checks.py
Gaps: StackExchange.Redis NOPERM and BUSY as RedisConnectionException come from a user and a script that blocked the handshake; a user that can run the handshake commands was not checked
Gaps: redis-rb cluster, redis-rs cluster and Predis cluster redirect behavior was not checked
Recheck: when StackExchange.Redis, redis-rb or ioredis change their connect handshake or ready check
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…d pages

Under the signatures for each client, the tab lists the error pages that data/errors.json ties to the command, with the exception or error type that client raises for each, linked to the page. No schema change to the 527 mapping files, and nothing to maintain per method. A mapping list on each client in data/client-exceptions.json turns the dropdown's client ids (redis_py, nredisstack_sync, php and so on) into entries of that file, so the block follows whatever clients the file covers.

The block shows only what the data says about a command by name, and that is much less than it sounds. An error that all commands that use keys can return, such as WRONGTYPE, has a scope in errors.json and no list of commands, so GET shows nothing while JSON.GET shows WRONGTYPE. Filling the gap by scope would be wrong: it would show WRONGTYPE for EXISTS. Of the 404 commands that errors.json names, about 250 have at least one linked page, and the generic ones (any command, any write) are not in it. The block says other errors are not listed and links to the error reference.

The block sits in each client's signature div, so the existing client switch shows and hides it, and a command with no mapping file (EXEC, for example) has no signatures and so no block. The index of command to pages is built once with partialCached from the same catalog the error list uses, so a message and its page cannot disagree with the error reference.

Learned: command-level error data is sparse because the server data records scopes, not commands, for the most common errors, so a per-command block can only be as complete as errors.json and must not guess from scope
Constraint: the block must only list errors that errors.json ties to the command by name, never errors inferred from a scope such as keys or write
Directive: To make GET and similar commands show WRONGTYPE, add the commands to the error's list in data/errors.json (and update_errors.py), not a scope rule in the template
Gaps: Checked in a browser on EVALSHA for redis-py; switching client in the dropdown was not clicked through, though the block lives inside each client's div
Recheck: when errors.json gains per-command lists for the key-scoped errors, or when a client is added to client-exceptions.json
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ine and refresh them in the update skill

`update_errors.py check` now fails when data/client-exceptions.json has no entry for a
common/ page, has an entry for a page that no longer exists, lists a client that isn't in
`order` or `versions`, or names a class that the client's last live run (client_baselines/)
didn't see. A class counts as seen when its last segment, with any trailing `)`, appears in
the recorded reply, which absorbs the Rust `ErrorKind::Server(Ask)` versus
`ServerErrorKind::Ask` spelling; "(none)" rows are skipped. Run against the 13 baselines
this found no false positives, and it does catch a renamed class or a deleted page entry.

`live_clients.py` now lists the pages whose reply differs from the saved baseline instead
of overwriting it, and saves only with `--accept`. A run with `--only` writes to
.errors-update/clients/ and is not compared, because a page such as wrongpass spans several
steps and a partial run reports false differences. `/update-error-reference` gains a step
that runs each bridge on the new image, updates the data by hand, and accepts the run.

Learned: a partial `live_checks` run (--only) can't be compared per page, since pages span steps
Constraint: client bridges share Docker ports 6550-6575, so run them one at a time
Directive: don't add `--only` support to the compare path, run the full set for a baseline
Recheck: the skill step is untested end to end on a real Redis release, run it at the next one
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

🧠 Redis Memory

Found 8 related items from repository history:

Memory updated at 0c1aa16

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

DOC-7253

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

host: '127.0.0.1', port: Number(port), connectTimeout: 5000, retryStrategy: () => null,
// By default ioredis waits while the server is loading its data. IOREDIS_READY_CHECK=0 turns that off.
...(process.env.IOREDIS_READY_CHECK === '0' ? { enableReadyCheck: false } : {}),
...(user ? { username: user } : {}), ...(password ? { password } : {}),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ioredis misses LOADING without env var

Medium Severity

The ioredis probe only sets enableReadyCheck: false when IOREDIS_READY_CHECK=0. live_clients.py and the skill command do not set that variable, so ioredis waits until the dataset finishes loading. The loading step then either times out, fails the “still loading” guard, or records no error instead of ReplyError.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e6f1262. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 985114f. A bridge can now declare STEP_ENV, and live_clients.py sets it for that step only. The ioredis bridge turns its ready check off for the loading step, so a normal run records ReplyError. I confirmed that with a live run and no env var set.

The errors index now has a section, "Errors without their own exception class", with a table
of the class that each client raises when it has no class of its own for an error. It is the
`generic` field of data/client-exceptions.json, so it can't drift from the per-page tables.
The `error-clients` shortcode takes `generic="true"` for it, and the Markdown/JSON expansion
handles both forms. Checked in a full Hugo build: the HTML table, index.html.md and index.json
all carry it, and the per-page tables are unchanged.

Learned: a Hugo build in a git worktree fails on develop/clients jupyter-example pages until data/examples.json and the other ignored data/ files are linked in; HUGO_IGNOREFILES='["content/develop/clients/.*"]' skips them
Directive: keep the generic table generated from client-exceptions.json, don't hand-write it in the page
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@andy-stark-redis
andy-stark-redis requested review from a team and paoloredis November 4, 2026 13:30
@andy-stark-redis andy-stark-redis self-assigned this Nov 4, 2026
@andy-stark-redis andy-stark-redis added the clients Client library docs label Nov 4, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

There are 4 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 47cedb8. Configure here.

def run(port, user, password, mode, *payload):
out = subprocess.run(['node', 'probe.mjs', str(port), user, password, mode, *payload], cwd=d,
capture_output=True, text=True, timeout=60, env=os.environ)
return parse(out.stdout, out.stderr)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ioredis loading check needs hidden env

Medium Severity

The ioredis probe only turns off enableReadyCheck when IOREDIS_READY_CHECK=0 is already in the environment, and run() forwards os.environ unchanged. live_clients.py never sets that variable, so a default ioredis run waits out LOADING, then loading() raises because the server is no longer loading. --accept refuses the baseline. The committed ioredis loading row was captured with that env var, but the skill and README do not mention it.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 47cedb8. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Already handled in 985114f. ioredis.py declares STEP_ENV = {"loading": {"IOREDIS_READY_CHECK": "0"}}, and live_clients.py sets it for that step only. I ran live_clients.py ioredis --only loading with the variable unset, and it recorded ReplyError: LOADING Redis is loading the dataset in memory.

if not any(name in r for r in replies):
problems.append(f'client-exceptions.json: {page}/{client} says {entry["class"]}, but the last '
f'{bridge} run got {replies[0][:100]!r}')
return problems

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Client check skips redis-py baseline

Medium Severity

check_clients() only compares data/client-exceptions.json to client_baselines/ for the bridge clients. redis-py is first in every table, but it is not in CLIENT_BASELINES and is never checked against live_baseline.json. A wrong redis-py class still lets update_errors.py check pass.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 47cedb8. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 0c1aa16. check_clients() now also reads live_baseline.json for redis-py, and a test checks that a wrong redis-py class is reported.

a, b = baseline[page].get(kind, []), results[page].get(kind, [])
if lc._same(a) != lc._same(b):
out.append((page, f'{kind}: was {str(a)[:200]!r}, now {str(b)[:200]!r}'))
return out

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Client diff ignores dropped pages

Low Severity

changed() skips any page that is missing from either the old baseline or the new run. live_checks.compare() reports those pages. A refresh that omits a page therefore prints a clean diff, while --accept still overwrites the baseline and drops that page.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 47cedb8. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 0c1aa16. changed() now reports a page that the run lost, and one with no baseline yet.

@paoloredis

Copy link
Copy Markdown
Collaborator

This looks great. Do you think maybe there should be a link from the client specific error-handling page to the error reference? E.g. here https://redis.io/docs/staging/DOC-7253-client-exceptions-errors/develop/clients/redis-py/error-handling/

@dwdougherty

Copy link
Copy Markdown
Collaborator

This looks great. Do you think maybe there should be a link from the client specific error-handling page to the error reference? E.g. here https://redis.io/docs/staging/DOC-7253-client-exceptions-errors/develop/clients/redis-py/error-handling/

+1

andy-stark-redis and others added 3 commits November 4, 2026 14:26
…oading check self-contained

The Jedis error-handling page's hierarchy now matches jedis 8.0.2, read with javap from the
jar. JedisClusterException extends JedisDataException, not JedisException. JedisConnectionException,
JedisValidationException and JedisClusterOperationException extend JedisException directly.
AbortedTransactionException isn't in 8.0.2 at all, so it is removed. The page now also lists
JedisBusyException, JedisBroadcastException, JedisProtocolNotSupportedException, JedisCacheException,
ClusterAggregationException and UnsupportedAggregationException.

Bugbot found that the ioredis probe only turned its ready check off when IOREDIS_READY_CHECK=0 was
set by hand, so a normal run of the loading step waited for the load to finish and didn't record
ReplyError. A bridge can now declare STEP_ENV, and live_clients.py sets those variables for that
step only. Run without the variable, ioredis now records ReplyError for loading.

Learned: ioredis waits on LOADING by default, so its loading check needs enableReadyCheck:false, but other steps keep the default
Constraint: AbortedTransactionException removal rests on the 8.0.2 jar, so recheck the hierarchy when the page's Jedis version moves
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A reviewer suggested linking from the client-specific error-handling pages to the new error
reference. Each of the nine client pages (redis-py, Jedis, node-redis and ioredis, Lettuce, go-redis,
StackExchange.Redis, Predis, redis-rb, redis-rs) gets one sentence, just before "Applying error
handling patterns", that names its client and links to the errors index. The overview page
gets one sentence under its categories table. The index is the target rather than common/ because
it has the lookup box as well as the common errors. Checked in a Hugo build with the clients
section's failing pages excluded: the links render as /develop/reference/errors/.

Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…t a client run loses

Two Bugbot findings on the client-exceptions checks, both valid.

`update_errors.py check` compared the data with the bridge baselines only, so a wrong redis-py class
passed, although redis-py is first in every table. It now also reads live_baseline.json, where
`verify` records the redis-py names, and a test changes a redis-py class and expects a problem.

`live_clients.py` skipped a page that was in the old baseline but not in the new run, so a refresh
that lost a page printed a clean diff and --accept dropped the page. It now reports a page that
the run lost, and one that has no baseline yet.

Two other Bugbot comments say the ioredis loading step needs IOREDIS_READY_CHECK=0 set by hand. They
were written against 985114f, which already has STEP_ENV, and a live run without the variable
records ReplyError, so they are stale.

Learned: Bugbot can review a commit and still flag what that commit fixes, so check the cited line before acting
Ticket: DOC-7253
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@andy-stark-redis
andy-stark-redis merged commit d6ec828 into main Nov 4, 2026
110 checks passed
@andy-stark-redis
andy-stark-redis deleted the DOC-7253-client-exceptions-errors branch November 4, 2026 15:51
@andy-stark-redis

Copy link
Copy Markdown
Contributor Author

Thanks @paoloredis and @dwdougherty - suggestions implemented.

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

Labels

clients Client library docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants