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.

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)

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.