BYOK (Mistral): session dies with bare "422 Unprocessable Entity" on the first tool call — assistant message sends both `content` and `tool_calls`
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 48/100
Direzione di ricerca
Begin with the CLI engine's runAgenticLoop entry point named in the report, then trace the session.error and errorOccurred handling used by the app's session error panel. Reproduce with a Mistral custom provider using devstral-latest or zai-glm-5-2 and a tool-call prompt. Done means the agentic session continues past the first tool call and the provider response body is visible in the error details.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Short summary
Sessions using a BYOK/custom Mistral model die with an undiagnosable "Unprocessable Entity" as soon as the model makes its first tool call
Affected version or release
1.1.21 (Windows desktop app; bundled CLI engine 1.0.85, also reproduced on 1.0.80)
Installation context
Local desktop app on Windows 11 (x86_64), personal account, worktree-backed repository sessions. Custom model provider configured against the Mistral API (https://api.mistral.ai).
What happened?
I configured the app with a Mistral API key as a custom model provider. The connection works — the app successfully enumerates the available models and they show up in the model picker (mistral-medium-latest, devstral-latest, ministral-8b-latest, zai-glm-5-2).
But every session I start with one of those models fails almost immediately. The session UI shows:
Unprocessable Entity
Error details:422 Unprocessable Entity
…and nothing else. The session is dead at that point. Screenshot attached below in context: the worktree is created, the session starts, the model answers with one sentence and successfully calls rename_branch, and then the turn collapses into the 422.
Digging into the local logs, the app/CLI is sending a request shape Mistral rejects. The first model call succeeds; the second one — the one replaying the assistant turn plus the tool result — is rejected in ~0.16s. The cause is that the assistant message is serialized with both a non-empty content and tool_calls, which Mistral's API explicitly disallows ("must have either content or tool_calls, but not both").
This correlates perfectly across three local sessions against the same provider, one of which works:
| Model (same Mistral provider) | First assistant message | Result |
|---|---|---|
mistral-medium-latest |
"content": "" + toolRequests |
✅ works |
devstral-latest |
"content": "I'll help you…" + toolRequests |
❌ 422 |
zai-glm-5-2 |
"content": "I'll analyze this repository…" + toolRequests |
❌ 422 |
The only variable is whether the model happened to emit a preamble sentence alongside the tool call — which the user cannot control — so in practice any Mistral BYOK model is unusable for agentic sessions.
There are two distinct app-side problems here:
- The request shape is invalid for this provider. Tracked in detail against the CLI engine as github/copilot-cli#4884; filing here too because this is where users hit it (the model picker offers models that then reliably fail on first tool call).
- The error surfaced in the session UI is unactionable. "422 Unprocessable Entity" with no provider response body means there is no way to tell whether this is a bad key, an unsupported model, a quota problem or a malformed payload. The provider's error body should be shown in the error details panel. I only found the cause by reading
~/.copilot/otel/copilot-otel.jsonland~/.copilot/session-state/<id>/events.jsonlby hand.
Secondary issue that will surface next once the above is fixed: Mistral validates tool_call_id as exactly 9 alphanumeric characters. Native Mistral models return compliant ids (KkQq9A6FI, GrkR6lLMv), but zai-glm-5-2 hosted on the same endpoint returns vLLM-style ids such as chatcmpl-tool-aae20b13990bb75a, which Mistral's own validator rejects on the follow-up request.
Steps to reproduce
- Add a custom model provider in the app pointing at
https://api.mistral.aiwith a valid Mistral API key. Note that model discovery works — the models are listed in the picker. - Create a new repository session and select
devstral-latest(orzai-glm-5-2). - Send a prompt that requires a tool call, e.g.
analyze this repo for me. - Watch the model reply with a sentence and run one tool successfully (e.g.
rename_branch). - The session immediately fails with
422 Unprocessable Entityand stops.
Expected behavior
The session should continue through the agentic loop. When targeting a provider that disallows an assistant message carrying both content and tool_calls, the client should split them into two messages (or drop/relocate the preamble text) rather than sending a payload the provider rejects.
Independently of that fix: the session error panel should surface the provider's HTTP response body, not just the bare status line, so a BYOK misconfiguration can be told apart from a provider-side rejection.
Additional context
From ~/.copilot/session-state/<session-id>/events.jsonl — the assistant message that triggers it:
{"type":"assistant.message","data":{"model":"zai-glm-5-2",
"content":"I'll analyze this repository for you. Let me start by exploring its structure and key files.",
"toolRequests":[{"toolCallId":"chatcmpl-tool-aae20b13990bb75a","name":"rename_branch",
"arguments":{"name":"analyze-repo-structure"},"type":"function"}]}}
The tool then executes successfully (tool.execution_complete, success: true), assistant.turn_start fires for turn 1, and immediately:
{"type":"session.error","data":{"errorType":"query","message":"422 Unprocessable Entity","statusCode":422}}
{"type":"hook.start","data":{"hookType":"errorOccurred","input":{"error":{"message":"\"422 Unprocessable Entity\""},"errorContext":"model_call","recoverable":true}}}
{"type":"hook.start","data":{"hookType":"sessionEnd","input":{"reason":"error","error":{"message":"422 Unprocessable Entity"}}}}
Note recoverable: true on the errorOccurred hook, yet the session is ended with reason: "error".
From ~/.copilot/otel/copilot-otel.jsonl — first call succeeded, second failed:
gen_ai.client.token.usage provider=openai server.address=api.mistral.ai
gen_ai.request.model=<provider-id>/zai-glm-5-2 gen_ai.response.model=zai-glm-5-2
input=48464 output=34 <- first call, OK
gen_ai.client.operation.duration error.type=SessionTurnError
gen_ai.operation.name=invoke_agent server.address=api.mistral.ai
duration=0.158s (no gen_ai.response.model) <- second call, 422
The app-side log (~/.copilot/logs/github-app.<pid>.log) shows the session being created normally with no hint of the failure:
github_app::session::manager::lifecycle: retained CLI for session creation
requested_model="zai-glm-5-2" remote_enabled=false
github_app::session::manager::lifecycle: fetched available models for session creation
requested_model="<provider-id>/zai-glm-5-2" model_count=30 auto_available=true
The stack trace captured in the error hook is unhelpful on current builds (napi_register_module_v1 frames only); on CLI 1.0.80 it pointed at runAgenticLoop in app.js.
Related: github/copilot-cli#4884 (same root cause, filed against the CLI engine).
Reference for the Mistral constraint: langchain-ai/langchain#21196.
- Lingua principale
- Nessun dato sulla lingua
- Stelle
- 2.1k
- Fork
- 157
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di github/app
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
Issue simili
-
货币战争手改优先级配置缺少列表元素类型校验(P3) Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
syfoud/Simulated_Scepter#172 ·
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
crossplane/crossplane#7859 ·
-
bot:ai-assisted component:compact-js status:untriaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
midnightntwrk/midnight-sdk#403 ·
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
nightscout/nocturne#1379 ·