github / github/copilot-cli

An empty model turn is persisted as `content: null` and permanently bricks the session

Đang mở
#4,269 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

area:models area:sessions
Ngôn ngữ chính
Shell
Star
11.2k
Fork
1.9k
Merge trung bình
14 giờ 16 phút
Pull request đã merge (30 ngày)
6

Mô tả

Summary

When a model returns a turn with no text content and no tool calls, Copilot persists it and replays it on every subsequent request as an assistant message with "content": null and no tool_calls. Against a strict OpenAI-compatible endpoint this is rejected, and because the bad message is now part of the conversation history, every following turn in that session fails identically. There is no way to recover the session from the UI.

Observed with a local model via Ollama's /v1/chat/completions, but the persistence/replay behaviour is provider-independent.

Error surfaced to the user

Execution failed: CAPIError: 400 invalid message content type: <nil>

Reproduction

  1. Point Copilot at an OpenAI-compatible endpoint that validates message shape (e.g. Ollama /v1/chat/completions).
  2. Use a model that occasionally ends a turn after reasoning without emitting content or a tool call.
  3. Once such a turn occurs, every subsequent message in that session fails with the error above.

The rejected payload shape reduces to:

curl http://localhost:11434/v1/chat/completions \
  -H 'Content-Type: application/json' -d '{
  "model": "<model>",
  "messages": [
    {"role": "user", "content": "hi"},
    {"role": "assistant", "content": null}
  ]}'
# 400 invalid message content type: <nil>

The same payload succeeds if content is "", or if the field is omitted entirely, or if tool_calls is present alongside content: null.

Why this looks like a Copilot-side bug

Per the OpenAI API schema for ChatCompletionRequestAssistantMessage:

The contents of the assistant message. Required unless tool_calls or function_call is specified.

So content: null is only valid when accompanied by tool_calls. The server accepting null with tool calls and rejecting it without is consistent with that rule — the emitted message is the non-conformant part.

Evidence from the session record

In ~/.copilot/session-state/<id>/events.jsonl, 36 of 37 assistant.message events were normal tool-calling turns (content: '' plus exactly one toolRequests entry). Exactly one had neither:

model: <local model> | outputTokens: 105
content: ''
toolRequests: []
reasoningText: "<105 tokens of reasoning, then the turn ended>"

Every request after that point produced session.error with the 400 above. The corresponding rows in session-store.db show assistant_response = NULL for all subsequent turns in that session.

Impact

A single empty model response is unrecoverable:

  • The session cannot be continued — every new message re-sends the poisoned history.
  • There is no UI affordance to delete, edit, or truncate the offending turn.
  • The only workaround is abandoning the session and starting a new one, losing the conversation.

This is most likely to affect users running local or smaller models, where empty turns are more common, but the failure mode is not specific to any provider.

Suggested fixes

Either would resolve it; the second is worth doing regardless:

  1. Serialize empty assistant content as "" rather than null when there are no tool calls (or omit the message entirely if it carries no content, tool calls, or other payload).
  2. Make an empty turn recoverable — drop a content-less, tool-call-less assistant message when rebuilding history, and/or let the user delete the last turn so a session can't be permanently bricked by one bad response.

Environment

  • Copilot CLI/SDK: 1.0.73
  • Copilot desktop app on macOS 26.5.2 (Apple Silicon)
  • Backend: Ollama 0.32.4, local model via /v1/chat/completions

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách theo dõi cách các sự kiện assistant.message từ ~/.copilot/session-state//events.jsonl được tuần tự hóa và phát lại vào các yêu cầu chat completion. So sánh sự kiện trống với các hàng assistant_response trong session-store.db và tái hiện sự cố với endpoint /v1/chat/completions của Ollama. Hoàn thành khi một lượt assistant trống không còn làm hỏng các yêu cầu tiếp theo và phiên có thể được khôi phục mà không cần từ bỏ phiên.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
shell
Lĩnh vực
api, backend, cli, databases
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
52/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.