Agent Teams: SendMessage writes mailbox JSON without `type` field → reader UI shows 'Unhandled case: [object Object]'
GitHub Issue Draft — Agent Teams SendMessage type field bug
Target repo: anthropics/claude-code
Submit URL: https://github.com/anthropics/claude-code/issues/new
---
Title
Agent Teams: SendMessage writes mailbox JSON without `type` field → reader UI shows "Unhandled case: [object Object]"
---
Body (paste as-is)
Summary
Khi sử dụng Agent Teams feature (TeamCreate + SendMessage), tool SendMessage ghi message vào mailbox JSON files (~/.claude/teams/<team>/inboxes/*.json) thiếu field type. Sau khi quit + reopen Cursor/VSCode, reader UI load message từ disk → render fail → popup error "Unhandled case: [object Object]" hiện mỗi lần extension poll mailbox (~100ms interval).
Environment
- Claude Code VSCode extension (cũng affects Cursor — same extension)
- Extension version:
cc_version=2.1.141.x(per log header) - OS: Windows 11
- Feature flag:
env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
Reproduction steps
- Enable Agent Teams: set env
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1in~/.claude/settings.json, restart Cursor - Use natural language to create team: "Create an agent team
test-teamwith planner/tester/fixer" - Run normal validation/coding work for ~1 hour — SendMessage gets called many times
- Quit Cursor without calling
TeamDelete(or without sending shutdown_request) - Wait some time (next day OK) — make sure Cursor fully restarted, not just reload
- Reopen workspace
- Result: popup "Unhandled case: [object Object] · View output logs · Troubleshooting resources" appears, recurring rapidly
Expected behavior
Either:
- (a)
SendMessagewrites message JSON vớitype: "message"field, OR - (b) Reader UI gracefully handles missing
typefield (fallback to "message" type)
Currently neither happens.
Actual behavior
Inbox JSON structure (~/.claude/teams/<team>/inboxes/<agent>.json):
[
{
"from": "team-lead",
"text": "...",
"summary": "...",
"timestamp": "2026-05-16T...",
"read": true
}
]
Missing type field. Reader expects type, gets undefined → fallback → [object Object] error popup.
Evidence
In our team fpa-validation: 79/79 messages across 8 inbox files missing the type field:
team-lead.json: 64 messagestester.json: 6 messagesplanner.json: 4 messagestester-sm135.json,planner-sm135.json,fixer-sm135.json,tester-2.json,fixer.json: rest
Output log excerpt (high-frequency polling)
[inProcessRunner] tester poll #53842: checking mailbox
[TeammateMailbox] readMailbox: read 64 message(s)
[TeammateMailbox] readUnreadMessages: 0 unread of 64 total
Polling happens every ~100ms across 4 teammates. Counter reached #56472 after several hours = ~564,000 mailbox reads → ~564,000 popup spawns.
Why in-session works but cross-restart fails (hypothesis)
- In-session: extension reads message from in-memory state (which may have
typeset at runtime by the dispatcher) → renders OK - Cross-restart: extension reads message from disk JSON file (persisted without
type) → fallback fail
Suggests bug in persistence/serialization layer: writer strips type field when writing to disk, reader expects it when loading from disk. In-memory ↔ disk schema mismatch.
Workaround
Client-side hook that runs on SessionStart, scans all team inboxes, injects "type": "message" for messages missing the field. Idempotent.
Sample Node.js script:
const fs = require('fs'), path = require('path'), os = require('os');
const TEAMS_DIR = path.join(os.homedir(), '.claude', 'teams');
if (!fs.existsSync(TEAMS_DIR)) process.exit(0);
for (const team of fs.readdirSync(TEAMS_DIR)) {
const inboxDir = path.join(TEAMS_DIR, team, 'inboxes');
if (!fs.existsSync(inboxDir)) continue;
for (const f of fs.readdirSync(inboxDir).filter(x => x.endsWith('.json'))) {
const fp = path.join(inboxDir, f);
const data = JSON.parse(fs.readFileSync(fp, 'utf8'));
if (!Array.isArray(data)) continue;
let patched = 0;
for (const msg of data) {
if (typeof msg === 'object' && msg !== null && !msg.type) { msg.type = 'message'; patched++; }
}
if (patched > 0) fs.writeFileSync(fp, JSON.stringify(data, null, 2), 'utf8');
}
}
Register vào .claude/settings.json:
"SessionStart": [{
"matcher": "",
"hooks": [{ "type": "command", "command": "node .claude/hooks/inbox-type-patch.cjs" }]
}]
Suggested fix (upstream)
Choose one:
- In
SendMessageSDK serializer: always injecttype: "message"(or whatever type was passed in payload) when serializing message to disk JSON - In reader/renderer: gracefully fallback to
type: "message"when undefined - Schema validation on write: throw error if required fields missing — surface bug at write time, not read time
Severity
Medium-High — feature still works in-session, but creates persistent popup spam after any restart with an active team. Workaround easy but should be unnecessary.
Related
- Tool:
SendMessage,TeamCreate,TeamDelete - Feature flag:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS - File path:
~/.claude/teams/<team>/inboxes/*.json
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗