{"record":{"id":"4c29d1b582928303","repo":"run-llama/llama_index","slug":"indexnode-obj-is-not-serializable-obj","errorCode":null,"errorMessage":"IndexNode obj is not serializable: {obj}","messagePattern":"IndexNode obj is not serializable: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/schema.py","lineNumber":975,"sourceCode":"    \"\"\"\n\n    index_id: str\n    obj: Any = None\n\n    def _serialize_obj(self) -> Any:\n        from llama_index.core.storage.docstore.utils import doc_to_json\n\n        try:\n            if self.obj is None:\n                return None\n            elif isinstance(self.obj, BaseNode):\n                return doc_to_json(self.obj)\n            elif isinstance(self.obj, BaseModel):\n                return self.obj.model_dump()\n            else:\n                return json.dumps(self.obj)\n        except Exception:\n            raise ValueError(\"IndexNode obj is not serializable: \" + str(self.obj))\n\n    @model_serializer(mode=\"wrap\")\n    def custom_model_dump(\n        self, handler: SerializerFunctionWrapHandler, info: SerializationInfo\n    ) -> Dict[str, Any]:\n        data = super().custom_model_dump(handler, info)\n        data[\"obj\"] = self._serialize_obj()\n        return data\n\n    def dict(self, **kwargs: Any) -> Dict[str, Any]:\n        data = super().dict(**kwargs)\n        data[\"obj\"] = self._serialize_obj()\n        return data\n\n    @classmethod\n    def from_text_node(\n        cls,\n        node: TextNode,","sourceCodeStart":957,"sourceCodeEnd":993,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/schema.py#L957-L993","documentation":"IndexNode can wrap an arbitrary Python object in its obj field (used by recursive retrieval over agents, query engines, retrievers). When serializing, _serialize_obj tries doc_to_json for BaseNode, model_dump for pydantic BaseModel, and json.dumps for everything else; if all fail it raises ValueError('IndexNode obj is not serializable').","triggerScenarios":"Creating IndexNode(obj=<non-serializable object>) — e.g. a raw retriever/query engine instance, a lambda, or an object holding open connections — and then persisting it (docstore.save, json()/model_dump, storage context persist).","commonSituations":"Recursive/agent retrieval where obj holds live objects; calling index.storage_context.persist() with object-bearing IndexNodes in the docstore; deep-copy or caching layers that serialize the node.","solutions":["Wrap the object in a pydantic BaseModel (or make it a dataclass supporting json.dumps) so one of the three serialization branches succeeds","Store a serializable reference (id/string/config) in obj and keep the live object in an object_map instead","Set obj=None for nodes that only need to exist as index structure"],"exampleFix":"# before\nindex_node = IndexNode(text=\"router\", obj=my_retriever)  # not serializable\n\n# after\nfrom pydantic import BaseModel\nclass RetrieverRef(BaseModel):\n    retriever_name: str\nindex_node = IndexNode(text=\"router\", obj=RetrieverRef(retriever_name=\"base\"))\n# live retriever stays in the object_map / recursive_retriever mapping","handlingStrategy":"validation","validationCode":"import json\nfrom pydantic import BaseModel\ndef obj_is_serializable(obj) -> bool:\n    if obj is None or isinstance(obj, (BaseNode, BaseModel)):\n        return True\n    try:\n        json.dumps(obj)\n        return True\n    except (TypeError, ValueError):\n        return False","typeGuard":"def index_node_safe_to_persist(n: \"IndexNode\") -> bool:\n    return obj_is_serializable(n.obj)","tryCatchPattern":null,"preventionTips":["Keep live objects in object_map, serializable refs in obj","Wrap third-party objects in a pydantic model before attaching","Persist only ref ids and rehydrate objects at load time"],"tags":["schema","serialization","index-node","recursive-retrieval"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}