langflow-ai/langflow · error · ValueError

provider_data must include exactly one of 'input' or 'messag

Error message

provider_data must include exactly one of 'input' or 'message'.

What it means

A Pydantic model_validator (mode='after') on WatsonxApiExecutionInput enforces an XOR: provider_data must carry exactly one of the string field 'input' or the object field 'message'. The check `has_input == has_message` fails when both are set or both are None, so the request is rejected as a ValidationError before the agent execution call is dispatched.

Source

Thrown at src/backend/base/langflow/api/v1/mappers/deployments/watsonx_orchestrate/payloads.py:594

    tool_display_name: NonEmptyString


class WatsonxApiExecutionInput(BaseModel):
    """API-facing provider_data payload for POST deployment runs."""

    model_config = {"extra": "forbid"}

    input: str | None = None
    message: dict[str, Any] | None = None
    thread_id: str | None = None

    @model_validator(mode="after")
    def validate_input_or_message_exclusive(self) -> WatsonxApiExecutionInput:
        has_input = self.input is not None
        has_message = self.message is not None
        if has_input == has_message:
            msg = "provider_data must include exactly one of 'input' or 'message'."
            raise ValueError(msg)
        return self


class _WatsonxApiAgentExecutionResultBase(BaseModel):
    """Shared fields for API-facing agent execution result payloads.

    All provider-owned identifiers and metadata live here inside
    ``provider_data``.  The enclosing response only carries Langflow-owned
    fields (``deployment_id``).  ``deployment_id`` (Langflow DB UUID) is
    intentionally omitted from this schema to avoid ownership confusion.
    """

    model_config = {"extra": "allow"}

    id: NonEmptyString | None = None
    agent_id: NonEmptyString | None = None
    thread_id: NonEmptyString | None = None
    status: str | None = None

View on GitHub (pinned to 976ec789d2)

Solutions

  1. For plain-text runs, send provider_data with only input: {"input": "hello", "thread_id": "..."}.
  2. For structured runs, send only message: {"message": {...}, "thread_id": "..."}.
  3. Audit client builders for a code path that sets both fields (e.g. copy-template then fill-in).
  4. Remove explicit null keys from the JSON before sending (null and absent are equivalent here, but neither counts as provided).

Example fix

# before (both set -> error)
provider_data = {"input": "hello", "message": {"role": "user", "content": "hello"}}

# after (text path)
provider_data = {"input": "hello"}
# or (structured path)
provider_data = {"message": {"role": "user", "content": "hello"}}
Defensive patterns

Strategy: validation

Validate before calling

def valid_execution_payload(pd: dict) -> bool:
    return (pd.get('input') is None) != (pd.get('message') is None)

Type guard

from typing import TypedDict

class TextExecution(TypedDict):
    input: str
    thread_id: str | None

class MessageExecution(TypedDict):
    message: dict
    thread_id: str | None

def is_text_execution(pd: dict) -> bool: return 'input' in pd and 'message' not in pd

Try / catch

Catch pydantic.ValidationError at the API boundary; if the message contains 'exactly one of', re-prompt/422 with a schema hint instead of retrying.

Prevention

When it happens

Trigger: POST to the Watsonx deployment execution endpoint with provider_data containing neither key ({}, only thread_id), or containing both ({'input': 'hi', 'message': {...}}).

Common situations: Defaulting both fields (they are Optional/None) and forgetting to set one; merging two client code paths (a simple-text path and a structured-message path) into one payload; sending {'input': None} explicitly, which still counts as None.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/9717cc9f5b71525a. Report an issue: GitHub.