{"record":{"id":"5b8ac66c283f0caa","repo":"iflytek/astron-agent","slug":"rediscache-only-accepts-values-that-can-be-pickled","errorCode":null,"errorMessage":"RedisCache only accepts values that can be pickled. ","messagePattern":"RedisCache only accepts values that can be pickled\\. ","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"core/plugin/link/domain/models/utils.py","lineNumber":337,"sourceCode":"        \"\"\"Get a field value from a Redis hash.\n\n        Args:\n            name: The hash name.\n            key: The field key within the hash.\n\n        Returns:\n            Any: The deserialized value from the hash field.\n\n        Raises:\n            TypeError: If the value cannot be deserialized.\n        \"\"\"\n        try:\n            result = self._client.hget(name=name, key=key)  # type: ignore[union-attr]\n            print(\"result: \", result)\n            result_str = result.decode(\"utf-8\")  # type: ignore[union-attr]\n            return json.loads(result_str)\n        except TypeError as exc:\n            raise TypeError(\n                \"RedisCache only accepts values that can be pickled. \"\n            ) from exc\n\n    def hash_del(self, name: str, *key: str) -> Tuple[bool, Dict[str, str]]:\n        \"\"\"Delete one or more fields from a Redis hash.\n\n        Args:\n            name: The hash name.\n            *key: Variable number of field keys to delete.\n\n        Returns:\n            tuple: (success_boolean, dict_of_failed_deletions)\n\n        Raises:\n            TypeError: If the operation fails due to type issues.\n        \"\"\"\n        try:\n            result = self._client.hdel(name, *key)","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/core/plugin/link/domain/models/utils.py#L319-L355","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"# before\nresult = self._client.hget(name=name, key=key)\nresult_str = result.decode(\"utf-8\")\nreturn json.loads(result_str)\n# after\nresult = self._client.hget(name=name, key=key)\nif result is None:\n    return None\nraw = result.decode(\"utf-8\") if isinstance(result, bytes) else result\nreturn json.loads(raw)","handlingStrategy":"type-guard","validationCode":"def hash_field_exists(svc, name: str, key: str) -> bool:\n    return bool(svc._client.hexists(name, key))","typeGuard":"def hash_result_ok(result) -> bool:\n    return result is not None and (isinstance(result, (bytes, str)))","tryCatchPattern":"try:\n    value = redis_service.hash_get(name, key)\nexcept TypeError:\n    value = None  # treat as cache miss; the message about pickling is misleading","preventionTips":["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."],"tags":["redis","cache","typeerror"],"backgroundTag":"type-mismatch","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-19T12:17:13.211Z"}