Skip to content

Python: fix(redis): wrap prefix string in list for IndexDefinition#13911

Open
armorbreak001 wants to merge 1 commit intomicrosoft:mainfrom
armorbreak001:fix/redis-index-prefix-iterable
Open

Python: fix(redis): wrap prefix string in list for IndexDefinition#13911
armorbreak001 wants to merge 1 commit intomicrosoft:mainfrom
armorbreak001:fix/redis-index-prefix-iterable

Conversation

@armorbreak001
Copy link
Copy Markdown

Summary

The Redis connector passes a plain string to IndexDefinition(prefix=...), but redis-py treats the prefix argument as an iterable. This causes each character of the collection name to become a separate key-space prefix.

For a collection named redis_json_list_data_model, the wire output becomes:

PREFIX 27 r e d i s _ j s o n _ l i s t _ d a t a _ m o d e l :

Instead of the expected:

PREFIX 1 redis_json_list_data_model:

Fix

Wrap the prefix string in a list so redis-py receives a single-element iterable.

Before: prefix=f"{self.collection_name}:"
After: prefix=[f"{self.collection_name}:"]

Fixes #13894

redis-py's IndexDefinition treats the prefix argument as an iterable.
Passing a plain string causes each character to become a separate
prefix (e.g., 'foo:' becomes ['f','o','o',':']). Wrap in a list
to send a single prefix.
@armorbreak001 armorbreak001 requested a review from a team as a code owner April 22, 2026 17:34
@moonbox3 moonbox3 added the python Pull requests for the Python Semantic Kernel label Apr 22, 2026
@github-actions github-actions Bot changed the title fix(redis): wrap prefix string in list for IndexDefinition Python: fix(redis): wrap prefix string in list for IndexDefinition Apr 22, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Automated Code Review

Reviewers: 4 | Confidence: 94%

✓ Correctness

This is a correct bug fix. The redis-py IndexDefinition constructor expects prefix to be a list of strings. The old code passed a bare string, which caused _append_prefix to iterate over individual characters (since strings are iterable in Python), producing malformed Redis FT.CREATE commands like PREFIX 18 c o l l e c t i o n _ n a m e : instead of the intended PREFIX 1 collection_name:. Wrapping the string in a list is the right fix.

✓ Security Reliability

This is a correct bug fix. The redis-py IndexDefinition._append_prefix method iterates over the prefix parameter and uses len(prefix) to emit the count. When a bare string was passed, len() returned the character count and the loop iterated character-by-character, producing a malformed Redis FT.CREATE command. Wrapping the string in a list is the correct fix. No security or reliability concerns are introduced by this change. A pre-existing instance of the same bug exists in the test file.

✗ Test Coverage

The fix correctly changes the prefix argument to IndexDefinition from a bare string to a list, which is necessary because _append_prefix iterates over the value and appends len(prefix) as the count — a bare string would produce PREFIX 5 t e s t : instead of PREFIX 1 test:. However, the existing test test_create_index (line 294) only asserts no exception is raised; it never verifies that create_index was called with an IndexDefinition whose prefix is a list. This means the bugfix has no regression test that would catch a revert. Additionally, test_create_index_manual (line 302) still passes prefix="test:" (a bare string) to IndexDefinition, demonstrating the same incorrect usage this PR fixes.

✗ Design Approach

This change fixes the immediate failure for the connector's internally generated index definition, but it does so narrowly. The same Redis IndexDefinition contract is still exposed unchanged through the manual index_definition path, and the repo's own test still models that path with prefix="test:", so the patch addresses one constructor call rather than the broader compatibility boundary around Redis prefix handling.

Flagged Issues

  • No test validates the fix: test_create_index (test_redis_store.py:294) calls ensure_collection_exists() but never asserts that create_index was invoked with an IndexDefinition whose prefix is a list. The mock is available but unchecked — a revert of this fix would not be caught by any test.
  • The fix is too narrow: ensure_collection_exists() now wraps the auto-generated prefix in a list, but the public/manual index_definition path is still passed through unchanged (redis.py:272-276), and the repo's own test still constructs IndexDefinition(prefix="test:", ...) at test_redis_store.py:302. Calers using that supported path will still get a malformed character-wise prefix sequence.

Suggestions

  • Update test_create_index_manual (test_redis_store.py:302) to use prefix=["test:"] instead of the bare string "test:", so the test demonstrates correct usage consistent with this fix.
  • In test_create_index, assert on the definition argument passed to the mocked create_index to verify the prefix is a single-element list (e.g., check that ['PREFIX', 1, 'test:'] appears in definition.args), providing regression coverage for this fix.
  • The legacy memory store at python/semantic_kernel/connectors/memory_stores/redis/redis_memory_store.py:132 has the same bare-string bug (prefix=f"{collection_name}:"). Consider fixing it there too if the legacy connector is still supported.
  • Normalize Redis prefix handling at the connector boundary instead of only in the default constructor path. A small helper that converts a string prefix to [prefix] before calling create_index() would make both the built-in and caller-supplied IndexDefinition paths compatible.

Automated review by armorbreak001's agents

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

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: Bug: Redis connector sends malformed FT.CREATE PREFIX (one prefix per character of collection name)

2 participants