{"record":{"id":"9717cc9f5b71525a","repo":"langflow-ai/langflow","slug":"provider-data-must-include-exactly-one-of-input","errorCode":null,"errorMessage":"provider_data must include exactly one of 'input' or 'message'.","messagePattern":"provider_data must include exactly one of 'input' or 'message'\\.","errorType":"validation","errorClass":"ValueError","httpStatus":422,"severity":"error","filePath":"src/backend/base/langflow/api/v1/mappers/deployments/watsonx_orchestrate/payloads.py","lineNumber":594,"sourceCode":"    tool_display_name: NonEmptyString\n\n\nclass WatsonxApiExecutionInput(BaseModel):\n    \"\"\"API-facing provider_data payload for POST deployment runs.\"\"\"\n\n    model_config = {\"extra\": \"forbid\"}\n\n    input: str | None = None\n    message: dict[str, Any] | None = None\n    thread_id: str | None = None\n\n    @model_validator(mode=\"after\")\n    def validate_input_or_message_exclusive(self) -> WatsonxApiExecutionInput:\n        has_input = self.input is not None\n        has_message = self.message is not None\n        if has_input == has_message:\n            msg = \"provider_data must include exactly one of 'input' or 'message'.\"\n            raise ValueError(msg)\n        return self\n\n\nclass _WatsonxApiAgentExecutionResultBase(BaseModel):\n    \"\"\"Shared fields for API-facing agent execution result payloads.\n\n    All provider-owned identifiers and metadata live here inside\n    ``provider_data``.  The enclosing response only carries Langflow-owned\n    fields (``deployment_id``).  ``deployment_id`` (Langflow DB UUID) is\n    intentionally omitted from this schema to avoid ownership confusion.\n    \"\"\"\n\n    model_config = {\"extra\": \"allow\"}\n\n    id: NonEmptyString | None = None\n    agent_id: NonEmptyString | None = None\n    thread_id: NonEmptyString | None = None\n    status: str | None = None","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/mappers/deployments/watsonx_orchestrate/payloads.py#L576-L612","documentation":"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.","triggerScenarios":"POST to the Watsonx deployment execution endpoint with provider_data containing neither key ({}, only thread_id), or containing both ({'input': 'hi', 'message': {...}}).","commonSituations":"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.","solutions":["For plain-text runs, send provider_data with only input: {\"input\": \"hello\", \"thread_id\": \"...\"}.","For structured runs, send only message: {\"message\": {...}, \"thread_id\": \"...\"}.","Audit client builders for a code path that sets both fields (e.g. copy-template then fill-in).","Remove explicit null keys from the JSON before sending (null and absent are equivalent here, but neither counts as provided)."],"exampleFix":"# before (both set -> error)\nprovider_data = {\"input\": \"hello\", \"message\": {\"role\": \"user\", \"content\": \"hello\"}}\n\n# after (text path)\nprovider_data = {\"input\": \"hello\"}\n# or (structured path)\nprovider_data = {\"message\": {\"role\": \"user\", \"content\": \"hello\"}}","handlingStrategy":"validation","validationCode":"def valid_execution_payload(pd: dict) -> bool:\n    return (pd.get('input') is None) != (pd.get('message') is None)","typeGuard":"from typing import TypedDict\n\nclass TextExecution(TypedDict):\n    input: str\n    thread_id: str | None\n\nclass MessageExecution(TypedDict):\n    message: dict\n    thread_id: str | None\n\ndef is_text_execution(pd: dict) -> bool: return 'input' in pd and 'message' not in pd","tryCatchPattern":"Catch pydantic.ValidationError at the API boundary; if the message contains 'exactly one of', re-prompt/422 with a schema hint instead of retrying.","preventionTips":["Model the two execution modes as separate builder functions (text vs structured) so both are never set.","Drop null keys when serializing payloads."],"tags":["pydantic","validation","watsonx","api-contract","xor-constraint"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}