Skip to content

Custom Mistral model returns "content": null for a tool call, failing Pydantic mapping #31121

@eddie-duvall-wwt

Description

@eddie-duvall-wwt

Checked other resources

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Example Code

from langchain_mistralai import ChatMistralAI
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_core.messages import AnyMessage, AIMessage, HumanMessage, SystemMessage
from langgraph.graph import START, StateGraph, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from typing import TypedDict, Annotated

class BasicAgent:
def init(self):
print("BasicAgent initialized.")
def call(self, question: str) -> str:
print(f"Agenct received question: {question}")

    system_prompt = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: [YOUR FINAL ANSWER].
    YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
    If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
    If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
    If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string."""


    search_tool = DuckDuckGoSearchRun()

    chat = ChatMistralAI(
        model="mistralai/Mistral-Small-3.1-24B-Instruct-2503",
        temperature=0,
        max_retries=2,
        max_tokens=2048,
        base_url="https://<custom-vpc-required-endpoint>/v1"
    )
    tools=[search_tool]
    print("Tools are ", tools)
    chat_with_tools = chat.bind_tools(tools)


    # Generate the AgentState and Agent graph
    class AgentState(TypedDict):
        messages: Annotated[list[AnyMessage], add_messages]

    def assistant(state: AgentState):
        #TODO seems to fail when it uses tools
        print("Messages being passed to chat_with_tools:", state["messages"])
        result = chat_with_tools.invoke(state["messages"])
        print("Chat response type:", type(result))
        print("Assistant Node Raw Result Content:", repr(result))
        return {
            "messages": [result],
        }

    builder = StateGraph(AgentState)

    builder.add_node("assistant", assistant)
    builder.add_node("tools", ToolNode(tools))

    builder.add_edge(START, "assistant")
    builder.add_conditional_edges(
        "assistant",
        # If the latest message requires a tool, route to tools
        # Otherwise, provide a direct response
        tools_condition, # Checks the *last* message: if tool_calls, returns "tools", else returns END
        {
            "tools": "tools", # If tool_calls detected, go to tool_node
            END: END          # Otherwise, finish the graph execution
        }
    )
    builder.add_edge("tools", "assistant")
    agent = builder.compile()

    messages = [
        SystemMessage(content=system_prompt),
        HumanMessage(content=question)
    ]

    print("\n--- Invoking Agent ---")
    final_state = {}

    try:
        # Invoke the agent. The state will accumulate messages.
        final_state = agent.invoke({"messages": messages}) # Pass the whole state dictionary
        print("\n--- Agent Invocation Finished ---")
        # Print the *final* messages list from the returned state
        if "messages" in final_state and final_state["messages"]:
             print("Final Agent State Messages:", final_state["messages"])
             # You usually want the content of the *last* message as the final answer
             print("\nFinal Answer Message:", repr(final_state["messages"][-1]))
             if final_state["messages"][-1].content:
                 print("\nFinal Answer Content:", final_state["messages"][-1].content)
             else:
                 print("\nFinal Answer: (Tool call or empty content in last message)")

        else:
            print("Error: No messages found in the final state.")

    except Exception as e:
        print("\n--- Agent Invocation Error ---")
        import traceback
        print(f"An error occurred during agent execution: {e}")
        print(traceback.format_exc()) # Print full traceback for debugging

    return final_state

Error Message and Stack Trace (if applicable)

2 validation errors for AIMessage
content.str
Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]
content.list[union[str,dict[any,any]]]
Input should be a valid list [type=list_type, input_value=None, input_type=NoneType]

Description

I have code to test the custom endpoint via direct call
import requests
import json

url = "https://"

--- Replace with your actual auth mechanism ---

If no auth needed, set headers = {"Content-Type": "application/json"}

headers = {
"Content-Type": "application/json"
}

payload = {
"model": "mistralai/Mistral-Small-3.1-24B-Instruct-2503",
"messages": [
{
"role": "system",
"content": "You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: [YOUR FINAL ANSWER].\n YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.\n If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.\n If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.\n If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string."
},
{
"role": "user",
"content": "How many studio albums were published by Mercedes Sosa between 2000 and 2009 (included)? You can use the latest 2022 version of english wikipedia."
}
],
"temperature": 0,
"max_tokens": 2048,
"tools": [
{
"type": "function",
"function": {
"name": "duckduckgo_search_run",
"description": "A wrapper around DuckDuckGo Search. Useful for when you need to answer questions about current events. Input should be a search query.",
"parameters": {
"type": "object",
"properties": {
"query": {
"description": "The search query",
"type": "string"
}
},
"required": ["query"]
}
}
}
],
"tool_choice": "auto"
}

print("--- Sending Request ---")
try:
response = requests.post(url, headers=headers, json=payload, timeout=60) # Added timeout
print(f"Status Code: {response.status_code}")
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)

print("\n--- Raw Response Text ---")
print(response.text)

print("\n--- Response JSON (if valid) ---")
try:
    response_json = response.json()
    print(json.dumps(response_json, indent=2)) # Pretty print JSON
except json.JSONDecodeError:
    print("Response was not valid JSON.")

except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
except Exception as e:
print(f"An error occurred: {e}")

print("\n--- Request Finished ---")

---OUTPUT---

--- Sending Request ---
Status Code: 200

--- Raw Response Text ---
{"id":"chatcmpl-f55f434a734b49b98a971338abdf7b9e","object":"chat.completion","created":1746485603,"model":"mistralai/Mistral-Small-3.1-24B-Instruct-2503","choices":[{"index":0,"message":{"role":"assistant","reasoning_content":null,"content":null,"tool_calls":[{"id":"5Nnf5HttA","type":"function","function":{"name":"duckduckgo_search_run","arguments":"{"query": "Mercedes Sosa studio albums 2000 2009"}"}}]},"logprobs":null,"finish_reason":"tool_calls","stop_reason":null}],"usage":{"prompt_tokens":302,"total_tokens":342,"completion_tokens":40,"prompt_tokens_details":null},"prompt_logprobs":null}

--- Response JSON (if valid) ---
{
"id": "chatcmpl-f55f434a734b49b98a971338abdf7b9e",
"object": "chat.completion",
"created": 1746485603,
"model": "mistralai/Mistral-Small-3.1-24B-Instruct-2503",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"reasoning_content": null,
"content": null,
"tool_calls": [
{
"id": "5Nnf5HttA",
"type": "function",
"function": {
"name": "duckduckgo_search_run",
"arguments": "{"query": "Mercedes Sosa studio albums 2000 2009"}"
}
}
]
},
"logprobs": null,
"finish_reason": "tool_calls",
"stop_reason": null
}
],
"usage": {
"prompt_tokens": 302,
"total_tokens": 342,
"completion_tokens": 40,
"prompt_tokens_details": null
},
"prompt_logprobs": null
}

--- Request Finished ---

System Info

python -m langchain_core.sys_info

System Information

OS: Darwin
OS Version: Darwin Kernel Version 24.4.0: Fri Apr 11 18:33:47 PDT 2025; root:xnu-11417.101.15~117/RELEASE_ARM64_T6000
Python Version: 3.11.1 (main, Oct 2 2023, 16:07:08) [Clang 14.0.3 (clang-1403.0.22.14.1)]

Package Information

langchain_core: 0.3.58
langchain: 0.3.25
langchain_community: 0.3.23
langsmith: 0.3.39
langchain_mistralai: 0.2.10
langchain_text_splitters: 0.3.8
langgraph_sdk: 0.1.66

Optional packages not installed

langserve

Other Dependencies

aiohttp<4.0.0,>=3.8.3: Installed. No version info available.
async-timeout<5.0.0,>=4.0.0;: Installed. No version info available.
dataclasses-json<0.7,>=0.5.7: Installed. No version info available.
httpx: 0.28.1
httpx-sse<1,>=0.3.1: Installed. No version info available.
httpx-sse<1.0.0,>=0.4.0: Installed. No version info available.
httpx<1,>=0.25.2: Installed. No version info available.
jsonpatch<2.0,>=1.33: Installed. No version info available.
langchain-anthropic;: Installed. No version info available.
langchain-aws;: Installed. No version info available.
langchain-azure-ai;: Installed. No version info available.
langchain-cohere;: Installed. No version info available.
langchain-community;: Installed. No version info available.
langchain-core<1.0.0,>=0.3.49: Installed. No version info available.
langchain-core<1.0.0,>=0.3.51: Installed. No version info available.
langchain-core<1.0.0,>=0.3.56: Installed. No version info available.
langchain-core<1.0.0,>=0.3.58: Installed. No version info available.
langchain-deepseek;: Installed. No version info available.
langchain-fireworks;: Installed. No version info available.
langchain-google-genai;: Installed. No version info available.
langchain-google-vertexai;: Installed. No version info available.
langchain-groq;: Installed. No version info available.
langchain-huggingface;: Installed. No version info available.
langchain-mistralai;: Installed. No version info available.
langchain-ollama;: Installed. No version info available.
langchain-openai;: Installed. No version info available.
langchain-perplexity;: Installed. No version info available.
langchain-text-splitters<1.0.0,>=0.3.8: Installed. No version info available.
langchain-together;: Installed. No version info available.
langchain-xai;: Installed. No version info available.
langchain<1.0.0,>=0.3.24: Installed. No version info available.
langsmith-pyo3: Installed. No version info available.
langsmith<0.4,>=0.1.125: Installed. No version info available.
langsmith<0.4,>=0.1.17: Installed. No version info available.
numpy>=1.26.2;: Installed. No version info available.
numpy>=2.1.0;: Installed. No version info available.
openai-agents: Installed. No version info available.
opentelemetry-api: Installed. No version info available.
opentelemetry-exporter-otlp-proto-http: Installed. No version info available.
opentelemetry-sdk: Installed. No version info available.
orjson: 3.10.18
packaging: 24.2
packaging<25,>=23.2: Installed. No version info available.
pydantic: 2.11.4
pydantic-settings<3.0.0,>=2.4.0: Installed. No version info available.
pydantic<3,>=2: Installed. No version info available.
pydantic<3.0.0,>=2.5.2;: Installed. No version info available.
pydantic<3.0.0,>=2.7.4: Installed. No version info available.
pydantic<3.0.0,>=2.7.4;: Installed. No version info available.
pytest: Installed. No version info available.
PyYAML>=5.3: Installed. No version info available.
requests: 2.32.3
requests-toolbelt: 1.0.0
requests<3,>=2: Installed. No version info available.
rich: 14.0.0
SQLAlchemy<3,>=1.4: Installed. No version info available.
tenacity!=8.4.0,<10,>=8.1.0: Installed. No version info available.
tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available.
tokenizers<1,>=0.15.1: Installed. No version info available.
typing-extensions>=4.7: Installed. No version info available.
zstandard: 0.23.0

pip show langchain langchain-core langchain-mistralai pydantic
Name: langchain
Version: 0.3.25
Summary: Building applications with LLMs through composability
Home-page:
Author:
Author-email:
License: MIT
Location: /Users/duvalle/Documents/Final_Assignment/venv/lib/python3.11/site-packages
Requires: langchain-core, langchain-text-splitters, langsmith, pydantic, PyYAML, requests, SQLAlchemy
Required-by: langchain-community

Name: langchain-core
Version: 0.3.58
Summary: Building applications with LLMs through composability
Home-page:
Author:
Author-email:
License: MIT
Location: /Users/duvalle/Documents/Final_Assignment/venv/lib/python3.11/site-packages
Requires: jsonpatch, langsmith, packaging, pydantic, PyYAML, tenacity, typing-extensions
Required-by: langchain, langchain-community, langchain-mistralai, langchain-text-splitters, langgraph, langgraph-checkpoint, langgraph-prebuilt

Name: langchain-mistralai
Version: 0.2.10
Summary: An integration package connecting Mistral and LangChain
Home-page:
Author:
Author-email:
License: MIT
Location: /Users/duvalle/Documents/Final_Assignment/venv/lib/python3.11/site-packages
Requires: httpx, httpx-sse, langchain-core, pydantic, tokenizers
Required-by:

Name: pydantic
Version: 2.11.4
Summary: Data validation using Python type hints
Home-page:
Author:
Author-email: Samuel Colvin [email protected], Eric Jolibois [email protected], Hasan Ramezani [email protected], Adrian Garcia Badaracco [email protected], Terrence Dorsey [email protected], David Montague [email protected], Serge Matveenko [email protected], Marcelo Trylesinski [email protected], Sydney Runkle [email protected], David Hewitt [email protected], Alex Hall [email protected], Victorien Plot [email protected]
License:
Location: /Users/duvalle/Documents/Final_Assignment/venv/lib/python3.11/site-packages
Requires: annotated-types, pydantic-core, typing-extensions, typing-inspection
Required-by: fastapi, gradio, langchain, langchain-core, langchain-mistralai, langgraph, langsmith, pydantic-settings

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugRelated to a bug, vulnerability, unexpected error with an existing featurehelp wantedGood issue for contributorsinvestigateFlagged for investigationmistralai`langchain-mistralai` package issues & PRs

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions