langchain-ai/deepagents · error · RuntimeError

Offload server returned an invalid cancellation acknowledgem

Error message

Offload server returned an invalid cancellation acknowledgement.

What it means

`_cancel_server_offload` asks the remote offload server to cancel an in-flight compaction and validates the acknowledgement; if the response `status` is neither `cancelled` nor `finished`, it raises `RuntimeError`. This guards against a server speaking an unexpected protocol or returning malformed cancellations.

Source

Thrown at libs/code/deepagents_code/client/remote_client.py:84

    """Request cancellation and wait for the server's terminal acknowledgement.

    Returns:
        Server terminal status (`cancelled` or `finished`).

    Raises:
        RuntimeError: If the server returns an invalid acknowledgement.
    """
    response = await asyncio.wait_for(
        graph.client.http.post(
            f"/dcode/threads/{thread_id}/offload/{operation_id}/cancel",
            json={},
        ),
        timeout=_OFFLOAD_CANCEL_WAIT_SECONDS,
    )
    status = response.get("status") if isinstance(response, dict) else None
    if status not in {"cancelled", "finished"}:
        msg = "Offload server returned an invalid cancellation acknowledgement."
        raise RuntimeError(msg)
    return status


async def _await_offload_step[T](
    awaitable: Awaitable[T],
    *,
    graph: Any,  # noqa: ANN401  # untyped RemoteGraph client
    thread_id: str,
    operation_id: str,
) -> T:
    """Await one offload step and confirm server termination if cancelled.

    Returns:
        The awaited step's result.

    Raises:
        asyncio.CancelledError: After the server confirms the operation ended.
    """

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Upgrade client and server to matching versions so cancellation statuses align.
  2. Log the raw response to see the unexpected `status` value and add it to the accepted set if it is legitimately new.
  3. Check network path for proxies that could mangle the JSON response body.
  4. Retry the operation; if persistent, report a protocol bug to the server maintainers.

Example fix

// before: strict two-status check
if status not in {"cancelled", "finished"}: raise RuntimeError(msg)
// after: accept documented new status
if status not in {"cancelled", "finished", "expired"}: raise RuntimeError(msg)
Defensive patterns

Strategy: type-guard

Validate before calling

def is_valid_cancel_ack(resp) -> bool:
    return isinstance(resp, dict) and resp.get("status") in {"cancelled", "finished"}
# check before relying on the result
if not is_valid_cancel_ack(response): reconcile_with_server()

Type guard

def is_valid_cancel_ack(resp: object) -> TypeGuard[dict]:
    return isinstance(resp, dict) and resp.get("status") in {"cancelled", "finished"}

Try / catch

try:
    await _await_offload_step(pending)
except RuntimeError as exc:
    if "invalid cancellation acknowledgement" in str(exc):
        log_raw_response_and_retry()

Prevention

When it happens

Trigger: Calling `_await_offload_step` on a pending offload awaitable whose cancellation request returns a dict with an unknown `status` (or a non-dict response), after waiting up to `_OFFLOAD_CANCEL_WAIT_SECONDS`.

Common situations: Version mismatch between client and offload server (server returns new status values like `expired`); a proxy/gateway returning an HTML error page parsed oddly; server bugs acknowledging cancellation with an unexpected payload.

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/cc2d27c6f93169fb. Report an issue: GitHub.