{"repo":"NousResearch/hermes-agent","public_id":"134","display_label":"Mistral API 422 errors from invalid message fields","summary":"A cluster of issues and fixes addressing HTTP 422 errors when calling the Mistral API, caused by internal or unsupported fields (such as finish_reason and reasoning params) being included in API message payloads. The fixes involve stripping or skipping these fields before making API calls.","subsystem":null,"counts":{"members":5,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":3},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":253},"resolution":{"state":"resolved","by":"pr-253"},"freshness":{"state":"stale","last_verified_at":"2026-03-02T08:35:04+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.4},"fix_edges":[{"issue_number":134,"pr_number":253,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":134,"title":"Error code: 422 when calling mistral api","url":null,"state":"closed"},{"kind":"pr","number":138,"title":"fix: sanitize internal fields from API messages","url":null,"state":"closed","close_reason":{"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":250,"title":"fix(agent): strip finish_reason and internal fields before API calls","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#253","number":253}],"category":"uncategorized","implication":"needs_llm"},"merged":false,"is_fix_pr":true,"fix_tier":"suggested","fix_detail_withheld":true},{"kind":"pr","number":252,"title":"fix(agent): skip reasoning param for Mistral API to prevent 422 errors","url":null,"state":"closed","close_reason":{"category":"silent_close","implication":"active"},"merged":false},{"kind":"pr","number":253,"title":"fix(agent): strip finish_reason from assistant messages to fix Mistral 422 errors","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["run_agent.py"],"fix_hunks":[{"file":"run_agent.py","hunks":["@@ -2087,7 +2087,8 @@ def _build_api_kwargs(self, api_messages: list) -> dict:\n         _is_openrouter = \"openrouter\" in self.base_url.lower()\n         _is_nous = \"nousresearch\" in self.base_url.lower()\n \n-        if _is_openrouter or _is_nous:\n+        _is_mistral = \"api.mistral.ai\" in self.base_url.lower()\n+        if (_is_openrouter or _is_nous) and not _is_mistral:\n             if self.reasoning_config is not None:\n                 extra_body[\"reasoning\"] = self.reasoning_config\n             else:","@@ -2232,6 +2233,7 @@ def flush_memories(self, messages: list = None, min_turns: int = None):\n                     if reasoning:\n                         api_msg[\"reasoning_content\"] = reasoning\n                 api_msg.pop(\"reasoning\", None)\n+                api_msg.pop(\"finish_reason\", None)\n                 api_messages.append(api_msg)\n \n             if self._cached_system_prompt:","@@ -2859,6 +2861,9 @@ def run_conversation(\n                 # We've copied it to 'reasoning_content' for the API above\n                 if \"reasoning\" in api_msg:\n                     api_msg.pop(\"reasoning\")\n+                # Remove finish_reason - not accepted by strict APIs (e.g. Mistral)\n+                if \"finish_reason\" in api_msg:\n+                    api_msg.pop(\"finish_reason\")\n                 # Keep 'reasoning_details' - OpenRouter uses this for multi-turn reasoning context\n                 # The signature field helps maintain reasoning continuity\n                 api_messages.append(api_msg)\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}