iflytek/astron-agent · error · TypeError
RedisCache only accepts values that can be pickled.
Error message
RedisCache only accepts values that can be pickled.
What it means
hash_get() fetches a hash field with HGET, then calls result.decode('utf-8') and json.loads(). A TypeError is raised when result is None (field missing) or already a str (decode_mode not set to bytes), and the handler re-raises a misleading TypeError claiming the value 'cannot be pickled'. Despite the message, the actual cause is a bytes-decoding or JSON-deserialization type error.
Solutions
- Check the field exists first: if self._client.hexists(name, key) is False, treat as cache miss and return None instead of decoding.
- Guard the result: if result is None: return None before calling result.decode().
- Ensure the client does NOT use decode_responses=True (or handle str: skip .decode() when isinstance(result, str)).
- Ignore the misleading message — the chained exception (`from exc`) shows the true TypeError at the decode/json line; fix that condition.
Example fix
# before
result = self._client.hget(name=name, key=key)
result_str = result.decode("utf-8")
return json.loads(result_str)
# after
result = self._client.hget(name=name, key=key)
if result is None:
return None
raw = result.decode("utf-8") if isinstance(result, bytes) else result
return json.loads(raw) Defensive patterns
Strategy: type-guard
Validate before calling
def hash_field_exists(svc, name: str, key: str) -> bool:
return bool(svc._client.hexists(name, key)) Type guard
def hash_result_ok(result) -> bool:
return result is not None and (isinstance(result, (bytes, str))) Try / catch
try:
value = redis_service.hash_get(name, key)
except TypeError:
value = None # treat as cache miss; the message about pickling is misleading Prevention
- Do not construct the Redis client with decode_responses=True; this code assumes bytes.
- Treat missing fields as cache misses — check hexists or a None result before decoding.
- Ignore the 'pickle' wording: the real failure is None.decode() or a str.decode() type error.
When it happens
Trigger: HGET returns None because the hash name or field key does not exist, so result.decode raises TypeError: 'NoneType' object has no attribute 'decode'; the Redis client was created with decode_responses=True so result is already str and .decode() fails; a stored value is not valid for the decode/json path.
Common situations: Reading a cache key that was never written or has expired; constructing redis.Redis(..., decode_responses=True) elsewhere in config while hash_get assumes bytes; wrong hash name/key casing; relying on the misleading 'pickle' message and debugging the wrong direction (serialization vs missing key).
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/5b8ac66c283f0caa.
Report an issue: GitHub.
Appendix: source
Thrown at core/plugin/link/domain/models/utils.py:337
"""Get a field value from a Redis hash.
Args:
name: The hash name.
key: The field key within the hash.
Returns:
Any: The deserialized value from the hash field.
Raises:
TypeError: If the value cannot be deserialized.
"""
try:
result = self._client.hget(name=name, key=key) # type: ignore[union-attr]
print("result: ", result)
result_str = result.decode("utf-8") # type: ignore[union-attr]
return json.loads(result_str)
except TypeError as exc:
raise TypeError(
"RedisCache only accepts values that can be pickled. "
) from exc
def hash_del(self, name: str, *key: str) -> Tuple[bool, Dict[str, str]]:
"""Delete one or more fields from a Redis hash.
Args:
name: The hash name.
*key: Variable number of field keys to delete.
Returns:
tuple: (success_boolean, dict_of_failed_deletions)
Raises:
TypeError: If the operation fails due to type issues.
"""
try:
result = self._client.hdel(name, *key)View on GitHub (pinned to 5e758547a8)