{"record":{"id":"d5ee9fe8598840c7","repo":"langchain-ai/deepagents","slug":"offload-operation-must-use-the-agent-s-composite-b","errorCode":null,"errorMessage":"Offload operation must use the agent's composite backend","messagePattern":"Offload operation must use the agent's composite backend","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/offload_middleware.py","lineNumber":737,"sourceCode":"    backend: CompositeBackend,\n    operation: OffloadOperation,\n) -> None:\n    \"\"\"Publish the operation on the backend shared with the server runtime.\n\n    Args:\n        backend: Composite backend owned by the agent server.\n        operation: Offload implementation bound to that backend.\n\n    Raises:\n        ValueError: If compaction writes through a different backend.\n    \"\"\"\n    # The SDK requires `backend` in its constructor, so a real summarization\n    # middleware always has one; `None` here means a test double, which is\n    # allowed through rather than asserted against.\n    bound = getattr(operation._compaction._summarization, \"_backend\", None)\n    if bound is not None and bound is not backend:\n        msg = \"Offload operation must use the agent's composite backend\"\n        raise ValueError(msg)\n    setattr(backend, _OFFLOAD_OPERATION_ATTR, operation)\n\n\ndef offload_operation_from(backend: CompositeBackend) -> OffloadOperation | None:\n    \"\"\"Return the server operation published on `backend`, when available.\"\"\"\n    operation = getattr(backend, _OFFLOAD_OPERATION_ATTR, None)\n    return operation if isinstance(operation, OffloadOperation) else None\n\n\ndef _event_cutoff(event: object) -> int:\n    \"\"\"Return the absolute cutoff index carried by a `_summarization_event`.\n\n    Args:\n        event: A `_summarization_event` mapping (as persisted in state), or\n            `None`.\n\n    Returns:\n        The `cutoff_index`, or `0` when the event is missing or malformed.","sourceCodeStart":719,"sourceCodeEnd":755,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/offload_middleware.py#L719-L755","documentation":"`attach_offload_operation` publishes an OffloadOperation onto the agent's CompositeBackend via a private attribute. Before doing so it checks that the summarization middleware bound inside the operation's compaction is wired to that same backend; if the operation references a different backend instance, it raises ValueError so archive writes never bypass the composite backend.","triggerScenarios":"Calling `attach_offload_operation(backend, operation)` where `operation._compaction._summarization._backend` is a different CompositeBackend instance — e.g. building the operation against one backend and the agent against another, or rebuilding the agent after the operation was created.","commonSituations":"Agent reconstruction on config reload while reusing a stale OffloadOperation; constructing separate CompositeBackend objects in tests/DI wiring; order-of-initialization mistakes where the backend is recreated after attach.","solutions":["Create the OffloadOperation using the same CompositeBackend instance passed to the agent (via `create_cli_agent`).","Rebuild the operation after any backend reconstruction, then re-attach.","In tests, pass `None`-backed or matching test doubles — only mismatched real backends raise."],"exampleFix":"// before\nop = build_offload_operation(old_backend)\nagent = create_cli_agent(backend=new_backend, offload_operation=op)\n// after\nbackend = CompositeBackend(...)\nop = build_offload_operation(backend)\nagent = create_cli_agent(backend=backend, offload_operation=op)","handlingStrategy":"validation","validationCode":"assert agent.backend is backend, \"agent and attach target must share one CompositeBackend\"\nassert offload_operation_from(backend) is not None, \"operation not attached\"","typeGuard":"def operation_matches_backend(operation: OffloadOperation, backend: CompositeBackend) -> bool:\n    bound = getattr(operation._compaction._summarization, \"_backend\", None)\n    return bound is None or bound is backend","tryCatchPattern":"try:\n    attach_offload_operation(backend, operation)\nexcept ValueError as e:\n    if \"composite backend\" in str(e):\n        operation = rebuild_operation(backend)  # recreate against the live backend\n        attach_offload_operation(backend, operation)","preventionTips":["Construct the OffloadOperation from the same CompositeBackend instance the agent uses.","Rebuild and re-attach the operation whenever the backend or agent is recreated.","Assert backend identity once at startup wiring."],"tags":["wiring","backend","offload","configuration"],"backgroundTag":"backend-mismatch","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}