MoonshotAI / MoonshotAI/kimi-cli
Bug: kimi export crashes during context compaction — API 400 text content is empty
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 11.4k
- Forks
- 1.3k
- Avg merge
- 9h 47m
- Merged PRs (30d)
- 2
Description
Summary
Typing kimi export can fail with a Moonshot API 400 error when the session enters context compaction. The compaction message contains empty/whitespace-only TextParts, which the API rejects.
Environment
- kimi-cli version: 1.45.0
- Python version: 3.12.13
- OS: Linux 6.18.27-amd64-desktop-rolling (x86_64)
- Model: kimi-code/kimi-for-coding
Steps to Reproduce
- Start a session that accumulates enough context to trigger auto-compaction.
- Ensure some messages in history have empty or whitespace-only
TextParts (e.g., tool results with no text output). - Run
kimi export. - The shell begins compaction (
CompactionBegin) and immediately crashes.
Actual Behavior
2026-05-28 21:11:28.599 | CompactionBegin
2026-05-28 21:11:30.254 | StepInterrupted
2026-05-28 21:11:30.254 | ERROR | Context compaction failed at step 1: APIStatusError: Error code: 400 - text content is empty
Expected Behavior
kimi export should complete successfully even when the context contains messages with empty text content.
Root Cause
In kimi_cli/soul/compaction.py, SimpleCompaction.prepare() builds a compaction prompt by iterating over historical messages and appending their TextParts:
compact_message.content.extend(
part for part in msg.content if isinstance(part, TextPart)
)
This does not filter out TextParts where text == "" or text.strip() == "". When the resulting compaction message is sent to kosong.step(), the Moonshot API rejects it with:
{"error": {"message": "text content is empty", "type": "invalid_request_error"}}
A similar bug for tool messages was previously fixed (see #1663 in message.py), but the compaction path was missed.
Proposed Fix
Two defensive changes in kimi_cli/soul/compaction.py, method SimpleCompaction.prepare():
1. Filter empty text parts
compact_message.content.extend(
part for part in msg.content
if isinstance(part, TextPart) and part.text.strip()
)
2. Skip compaction if nothing meaningful remains
compact_message.content.append(TextPart(text=prompt_text))
if not any(
isinstance(p, TextPart) and p.text.strip()
for p in compact_message.content
):
return self.PrepareResult(compact_message=None, to_preserve=messages)
return self.PrepareResult(compact_message=compact_message, to_preserve=to_preserve)
Attachments
Sanitized session export (PII redacted): session-df52da1f-sanitized.zip
Related PR
- #2395
Additional Context
The crash occurs at the kosong.step() call inside SimpleCompaction.compact(), not during serialization of the final compacted result. Therefore the fix must be applied before the LLM call, not after.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in kimi_cli/soul/compaction.py at SimpleCompaction.prepare(), then trace the compaction call from SimpleCompaction.compact() to understand where the message is sent. Verify that empty or whitespace-only TextParts are excluded and that export completes, or skips compaction when no meaningful text remains.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100