redis/redis-py · error · RuntimeError

index_type must be one of {list(IndexType)}

Error message

index_type must be one of {list(IndexType)}

What it means

Raised by IndexDefinition._append_index_type when the index_type argument is not None and is not a member of the IndexType enum (HASH or JSON). The library refuses to emit an 'ON <type>' clause for an unknown type because Redis would reject the FT.CREATE anyway with a less helpful error. Pass an IndexType enum member or omit the argument.

Source

Thrown at redis/commands/search/index_definition.py:43

        payload_field=None,
        index_type=None,
    ):
        self.args = []
        self._append_index_type(index_type)
        self._append_prefix(prefix)
        self._append_filter(filter)
        self._append_language(language_field, language)
        self._append_score(score_field, score)
        self._append_payload(payload_field)

    def _append_index_type(self, index_type):
        """Append `ON HASH` or `ON JSON` according to the enum."""
        if index_type is IndexType.HASH:
            self.args.extend(["ON", "HASH"])
        elif index_type is IndexType.JSON:
            self.args.extend(["ON", "JSON"])
        elif index_type is not None:
            raise RuntimeError(f"index_type must be one of {list(IndexType)}")

    def _append_prefix(self, prefix):
        """Append PREFIX."""
        if prefix is None:
            raise TypeError("prefix must be provided")
        if len(prefix) > 0:
            prefix = list_or_args(prefix, [])
            self.args.append("PREFIX")
            self.args.append(len(prefix))
            for p in prefix:
                self.args.append(p)

    def _append_filter(self, filter):
        """Append FILTER."""
        if filter is not None:
            self.args.append("FILTER")
            self.args.append(filter)

View on GitHub (pinned to da03cdc7e8)

Solutions

  1. Import the enum and pass a member: from redis.commands.search.index_definition import IndexDefinition, IndexType, then index_type=IndexType.HASH.
  2. If you do not care about the ON clause, omit index_type entirely (defaults to None, server picks HASH).
  3. If building from dynamic input, normalize it first: IndexType[str(val).upper()] to convert a string to the enum.

Example fix

// before
IndexDefinition(prefix=['doc:'], index_type='HASH')
// after
from redis.commands.search.index_definition import IndexDefinition, IndexType
IndexDefinition(prefix=['doc:'], index_type=IndexType.HASH)
Defensive patterns

Strategy: type-guard

Validate before calling

from redis.commands.search.index_definition import IndexType

def coerce_index_type(val):
    if val is None or isinstance(val, IndexType):
        return val
    if isinstance(val, str):
        return IndexType[val.upper()]
    raise ValueError(f"Cannot coerce {val!r} to IndexType")

# usage: IndexDefinition(prefix=p, index_type=coerce_index_type(raw))

Type guard

from redis.commands.search.index_definition import IndexType

def is_index_type(val) -> bool:
    return val is None or isinstance(val, IndexType)

Try / catch

try:
    IndexDefinition(prefix=p, index_type=raw)
except RuntimeError:
    # fall back to default or re-raise with guidance
    IndexDefinition(prefix=p)

Prevention

When it happens

Trigger: Constructing IndexDefinition with a plain string or integer instead of the enum, e.g. IndexDefinition(prefix=['doc:'], index_type='HASH') or IndexDefinition(index_type=1). The check fires in __init__ before any Redis round-trip.

Common situations: Copy-pasting a string literal 'HASH'/'JSON' from documentation or examples that show the wire token rather than the Python enum; passing a value read from a config file/YAML as a raw string; upgrading code that previously used magic strings.

Related errors


AI-assisted analysis of redis/redis-py@da03cdc7e8 (2026-08-04). Data as JSON: /data/errors/befc22cc7e97b9f4.json. Report an issue: GitHub.