langchain-ai/deepagents · error · TypeError

operation_id must be a non-empty string.

Error message

operation_id must be a non-empty string.

What it means

Every offload operation is identified by `operation_id`, which must be a non-empty string. The check rejects missing keys, None, empty strings, and non-string values so operations can be tracked and correlated reliably. This fires inside _operation_payload before context validation.

Source

Thrown at libs/code/deepagents_code/offload_api.py:522

    Args:
        payload: Decoded request JSON.

    Returns:
        Operation id, runtime context, and accumulated hook responses.

    Raises:
        TypeError: If the payload or a structured field has the wrong shape.
    """
    if not isinstance(payload, dict):
        msg = "Offload request must be a JSON object."
        raise TypeError(msg)
    operation_id = payload.get("operation_id")
    context = payload.get("context")
    responses = payload.get("hook_responses", {})
    if not isinstance(operation_id, str) or not operation_id:
        msg = "operation_id must be a non-empty string."
        raise TypeError(msg)
    if not isinstance(context, dict):
        msg = "context must be a JSON object."
        raise TypeError(msg)
    if not isinstance(responses, dict):
        msg = "hook_responses must be a JSON object."
        raise TypeError(msg)
    validated_context = {str(key): value for key, value in context.items()}
    _validate_context(validated_context)
    return (
        operation_id,
        _strip_transport_model_params(validated_context),
        {str(key): value for key, value in responses.items()},
    )


def _hydrate_state(values: object) -> _OffloadState:
    """Hydrate serialized checkpoint messages for the compaction service.

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Generate an id if you do not have one: operation_id=str(uuid.uuid4()) (or str(uuid4()) before payload construction).
  2. Cast UUIDs/ids to str(...) at payload-build time.
  3. Add a guard: if not operation_id: raise/skip with a clear log before calling offload().
  4. Fix the upstream producer that emits empty operation ids.

Example fix

// before
payload = {"context": ctx}
// after
import uuid
payload = {"operation_id": str(uuid.uuid4()), "context": ctx}
Defensive patterns

Strategy: validation

Validate before calling

def validate_operation_id(payload):
    op_id = payload.get("operation_id")
    if not isinstance(op_id, str) or not op_id:
        raise ValueError("operation_id must be a non-empty string before calling offload")

Type guard

def has_operation_id(payload) -> bool:
    op_id = payload.get("operation_id") if isinstance(payload, dict) else None
    return isinstance(op_id, str) and bool(op_id)

Try / catch

try:
    state = await offload(thread_id, payload)
except TypeError as exc:
    if "operation_id" in str(exc):
        import uuid
        payload["operation_id"] = str(uuid.uuid4())
        state = await offload(thread_id, payload)
    else:
        raise

Prevention

When it happens

Trigger: Calling offload() with payload={'context': {...}} (key omitted), {'operation_id': ''}, {'operation_id': None}, {'operation_id': 123}, or {'operation_id': some_uuid.UUID instance}.

Common situations: Constructing request dicts by hand and forgetting the id, an upstream generator producing empty ids for skipped events, passing a UUID object instead of its string form, or template/config substitution leaving the field blank.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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