langchain-ai/deepagents · error · ValueError

External event payload must be a non-empty string

Error message

External event payload must be a non-empty string

What it means

Alongside kind validation, `ExternalEvent.__post_init__` requires a non-empty, non-whitespace payload (`if not self.payload or not self.payload.strip()`). An empty payload carries no actionable information, so the dataclass rejects it at construction time rather than letting an inert event flow through the bus.

Solutions

  1. Populate the payload with meaningful content on the producer side before emitting.
  2. Guard the producer: skip events whose payload is empty or whitespace-only.
  3. Strip and validate incoming socket messages before wrapping them in `ExternalEvent`.

Example fix

// before
ExternalEvent(kind="signal", payload=msg.strip().split(":")[1])  # may be empty
// after
parts = msg.strip().split(":", 1)
if len(parts) == 2 and parts[1].strip():
    ExternalEvent(kind="signal", payload=parts[1])
Defensive patterns

Strategy: validation

Validate before calling

def safe_event(kind: str, payload: str):
    if not payload or not payload.strip():
        return None
    return ExternalEvent(kind=kind, payload=payload)

Type guard

def has_payload(payload: object) -> bool:
    return isinstance(payload, str) and bool(payload.strip())

Try / catch

try:
    event = ExternalEvent(kind=kind, payload=payload)
except ValueError as exc:
    logger.warning("Dropping empty-payload event: %s", exc)
    event = None

Prevention

When it happens

Trigger: Constructing `ExternalEvent(kind=<valid>, payload="")` or `payload=" "` — e.g. a socket producer forwarding a blank line, or splitting an incoming message without checking for empty segments.

Common situations: Unix-socket clients sending an empty JSON field; message framing that splits on newlines yielding empty trailing segments; templates/config generating empty payloads from unfilled variables.

Related errors


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

Appendix: source

Thrown at libs/code/deepagents_code/event_bus.py:78

    payload: str
    source: str
    bypass: BypassTier = BypassTier.QUEUED
    correlation_id: str | None = None

    def __post_init__(self) -> None:
        """Validate invariants for direct construction.

        Raises:
            ValueError: If `kind` is not a known kind, the payload is empty
                or whitespace-only, or the kind is `"signal"` but the payload
                is not a recognized signal name.
        """
        if self.kind not in _VALID_KINDS:
            msg = f"Unknown external event kind: {self.kind!r}"
            raise ValueError(msg)
        if not self.payload or not self.payload.strip():
            msg = "External event payload must be a non-empty string"
            raise ValueError(msg)
        if self.kind == "signal" and self.payload.strip().lower() not in _VALID_SIGNALS:
            msg = (
                f"Unknown external signal: {self.payload!r}; "
                f"expected one of {sorted(_VALID_SIGNALS)}"
            )
            raise ValueError(msg)


class EventSource(Protocol):
    """Source of external events for the Textual app.

    Implementations must be safe to `stop()` even when `start()` failed
    partway through; the app always invokes `stop()` from a `finally` block.
    """

    async def start(
        self,
        sink: Callable[[ExternalEvent], Awaitable[None]],

View on GitHub (pinned to a1af029e6e)