Skip to content

fix(pubsub): avoid UnicodeDecodeError on reconnect with binary channel names#3944

Merged
petyaslavova merged 4 commits intoredis:masterfrom
skylarkoo7:fix-3912-binary-channel-reconnect
Feb 23, 2026
Merged

fix(pubsub): avoid UnicodeDecodeError on reconnect with binary channel names#3944
petyaslavova merged 4 commits intoredis:masterfrom
skylarkoo7:fix-3912-binary-channel-reconnect

Conversation

@skylarkoo7
Copy link
Copy Markdown
Contributor

Summary

When a binary channel name that is not valid UTF-8 is subscribed via positional arguments (without a callback handler), the PubSub.on_connect reconnection logic raises UnicodeDecodeError. This happens because on_connect force-decodes every stored channel key to pass it as a keyword argument to subscribe()/psubscribe().

The fix splits channels into two groups during reconnection:

  • With handlers (originally passed as kwargs): decoded and re-passed as kwargs — their names are guaranteed decodable since Python requires string keyword arguments
  • Without handlers (originally passed as positional args): passed as raw positional args — no decoding required, preserving arbitrary binary names

Changes

  • redis/client.py — sync PubSub.on_connect: split channels, patterns, and shard_channels by handler presence
  • redis/asyncio/client.py — async PubSub.on_connect: same split for channels and patterns
  • tests/test_pubsub.py — added test_resubscribe_binary_channel_on_reconnection and test_resubscribe_binary_pattern_on_reconnection
  • tests/test_asyncio/test_pubsub.py — async equivalents of the above tests

Test plan

  • New tests subscribe to deliberately invalid UTF-8 channel/pattern names, force a disconnect, then verify get_message() triggers reconnection and resubscription without raising UnicodeDecodeError
  • Existing reconnection tests (test_resubscribe_to_channels_on_reconnection, test_resubscribe_to_patterns_on_reconnection) continue to pass, confirming backward compatibility for string channel names with and without handlers

Fixes #3912

…l names

Channels subscribed as positional arguments (without a callback handler)
may carry binary names that are not valid in the connection's encoding
(e.g. arbitrary bytes that are not valid UTF-8).  The existing
`on_connect` method decoded every channel name via `force=True` to pass
them as keyword arguments to `subscribe`/`psubscribe`, which raised
`UnicodeDecodeError` for these channels.

Split the reconnection logic: channels with handlers are decoded and
passed as kwargs (they were originally subscribed as kwargs, so their
names are guaranteed decodable); channels without handlers are passed as
positional args, preserving the original bytes.

Applied the same fix to:
- async PubSub.on_connect (channels and patterns)
- sync PubSub.on_connect (channels, patterns, and shard_channels)

Added tests for binary channel and pattern reconnection in both sync
and async test suites.

Fixes redis#3912
@jit-ci
Copy link
Copy Markdown

jit-ci bot commented Feb 9, 2026

Hi, I’m Jit, a friendly security platform designed to help developers build secure applications from day zero with an MVS (Minimal viable security) mindset.

In case there are security findings, they will be communicated to you as a comment inside the PR.

Hope you’ll enjoy using Jit.

Questions? Comments? Want to learn more? Get in touch with us.

@petyaslavova
Copy link
Copy Markdown
Collaborator

Hi @skylarkoo7, thank you for your contribution! We will have a look at it.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes PubSub reconnection resubscribe logic to avoid UnicodeDecodeError when previously-subscribed channel/pattern names are arbitrary binary (non-UTF-8) and were originally subscribed without handlers (positional args).

Changes:

  • Update sync and asyncio PubSub.on_connect to split stored subscriptions into “with handlers” (replayed as decoded **kwargs) vs “without handlers” (replayed as raw positional args).
  • Add sync + asyncio tests covering reconnect/resubscribe for invalid UTF-8 binary channels and patterns.
  • Minor test assertion formatting adjustment.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
redis/client.py Sync PubSub.on_connect now resubscribes binary/no-handler channels/patterns/shard channels as positional args to avoid forced decoding.
redis/asyncio/client.py Async PubSub.on_connect uses the same handler-aware split for channels and patterns.
tests/test_pubsub.py Adds regression tests for binary channel/pattern resubscription on reconnect (sync).
tests/test_asyncio/test_pubsub.py Adds async equivalents of the new binary reconnect/resubscribe regression tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@petyaslavova petyaslavova added the maintenance Maintenance (CI, Releases, etc) label Feb 23, 2026
Copy link
Copy Markdown
Collaborator

@petyaslavova petyaslavova left a comment

Choose a reason for hiding this comment

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

LGTM.

@petyaslavova petyaslavova merged commit b4e0129 into redis:master Feb 23, 2026
63 checks passed
petyaslavova added a commit that referenced this pull request Feb 25, 2026
…l names (#3944)

* fix(pubsub): avoid UnicodeDecodeError on reconnect with binary channel names

Channels subscribed as positional arguments (without a callback handler)
may carry binary names that are not valid in the connection's encoding
(e.g. arbitrary bytes that are not valid UTF-8).  The existing
`on_connect` method decoded every channel name via `force=True` to pass
them as keyword arguments to `subscribe`/`psubscribe`, which raised
`UnicodeDecodeError` for these channels.

Split the reconnection logic: channels with handlers are decoded and
passed as kwargs (they were originally subscribed as kwargs, so their
names are guaranteed decodable); channels without handlers are passed as
positional args, preserving the original bytes.

Applied the same fix to:
- async PubSub.on_connect (channels and patterns)
- sync PubSub.on_connect (channels, patterns, and shard_channels)

Added tests for binary channel and pattern reconnection in both sync
and async test suites.

Fixes #3912

* Applying review comments.

---------

Co-authored-by: petyaslavova <petya.slavova@redis.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Maintenance (CI, Releases, etc)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Subscribing to a binary channel name triggers UnicodeDecodeError on reconnect

3 participants