[BUG] IDE notifications sent right after ide_connected are silently dropped

Status Open
Reported on v2.1.288
Maintainer reply None cached
Activity 0 comments · opened Oct 3, 2026

Preflight Checklist

  • [X] I have searched existing issues and this hasn't been reported yet
  • [X] This is a single bug report (please file separate reports for different bugs)
  • [X] I am using the latest version of Claude Code

What's Wrong?

When an IDE integration sends selection_changed to Claude Code right after it receives ide_connected, the notification is dropped silently. The new session shows no ⧉ N lines selected, and the selection does not reach the model until the user moves the cursor. Nothing appears in the UI or in --debug-file.

Claude Code seems to start listening for IDE notifications some time after it sends ide_connected: on my machine a notification sent 0 ms after it is always lost, one sent 10 ms after it is usually lost, and from 25 ms on it arrives. No message tells the IDE when Claude Code is ready. The last thing the IDE receives is the tools/list request, and a notification sent 10 ms after answering it was still lost.

IDE integrations work around this with a fixed delay. The official VS Code extension waits 500 ms after the connection before it sends the current selection, and the Obsidian plugin Claude Code IDE is adopting the same delay. A fixed delay is a guess: on Windows the window was reported at up to about 400 ms.

What Should Happen?

A notification sent after ide_connected is processed. Either Claude Code subscribes to IDE notifications before it sends ide_connected, or it sends a separate notification once it is ready, so the IDE can push its current state then.

Error Messages/Logs

# repro server log, DELAY_MS=0, `claude --ide`: selection lost, no indicator
+    0 ms  websocket open
+    2 ms  recv initialize
+    4 ms  send response id=0
+    6 ms  recv notifications/initialized
+    6 ms  recv ide_connected
+    7 ms  recv tools/list
+    7 ms  send response id=1
+    7 ms  send selection_changed (3 lines)

# DELAY_MS=10: tools/list answered at +5 ms, selection sent 10 ms later, still lost
+    4 ms  recv ide_connected
+    5 ms  recv tools/list
+    5 ms  send response id=1
+   15 ms  send selection_changed (3 lines)

# DELAY_MS=500: `⧉ 3 lines selected` appears
+    7 ms  recv ide_connected
+    8 ms  recv tools/list
+  509 ms  send selection_changed (3 lines)

Steps to Reproduce

A minimal IDE server, no editor needed. It writes a lock file to ~/.claude/ide/, answers initialize and tools/list, and sends one selection_changed (3 lines) DELAY_MS after it receives ide_connected. The lock file is removed on Ctrl+C.

  1. Save the script below as repro-ide-server.mjs in an empty directory, then run mkdir workspace && npm i ws && DELAY_MS=0 node repro-ide-server.mjs workspace
  2. In a second terminal: cd workspace && claude --ide (accept the trust dialog if it appears)
  3. Look at the prompt input: no ⧉ 3 lines selected
  4. Quit Claude Code, restart the server with DELAY_MS=500, repeat step 2: the indicator appears

The same happens when connecting from a running session with /ide.

<details>
<summary>repro-ide-server.mjs (Node 18+, ws 8)</summary>

import { WebSocketServer } from "ws";
import { randomUUID } from "node:crypto";
import { mkdirSync, realpathSync, rmSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { join, resolve } from "node:path";

const delayMs = Number(process.env.DELAY_MS ?? 0);
// Claude Code matches its real cwd against workspaceFolders (/tmp is a symlink on macOS)
const workspace = realpathSync(resolve(process.argv[2] ?? process.cwd()));
const filePath = join(workspace, "repro.txt");
writeFileSync(filePath, "alpha\nbeta\ngamma\n");

const authToken = randomUUID();
const wss = new WebSocketServer({ host: "127.0.0.1", port: 0 });
await new Promise((ready) => wss.once("listening", ready));
const { port } = wss.address();

const lockDir = join(homedir(), ".claude", "ide");
const lockFile = join(lockDir, `${port}.lock`);
mkdirSync(lockDir, { recursive: true });
writeFileSync(lockFile, JSON.stringify({
  pid: process.pid,
  workspaceFolders: [workspace],
  ideName: "ReproIDE",
  transport: "ws",
  authToken,
}));
const cleanup = () => { rmSync(lockFile, { force: true }); process.exit(0); };
process.on("SIGINT", cleanup);
process.on("SIGTERM", cleanup);
console.log(`ReproIDE on port ${port}, DELAY_MS=${delayMs}, workspace ${workspace}`);

wss.on("connection", (ws, req) => {
  if (req.headers["x-claude-code-ide-authorization"] !== authToken) return ws.close();
  const t0 = performance.now();
  const log = (line) => console.log(`+${(performance.now() - t0).toFixed(0).padStart(5)} ms  ${line}`);
  log("websocket open");

  ws.on("message", (raw) => {
    const msg = JSON.parse(raw);
    log(`recv ${msg.method ?? `response id=${msg.id}`}`);

    if (msg.method === "ide_connected") {
      setTimeout(() => {
        ws.send(JSON.stringify({
          jsonrpc: "2.0",
          method: "selection_changed",
          params: {
            filePath,
            text: "alpha\nbeta\ngam",
            selection: { start: { line: 0, character: 0 }, end: { line: 2, character: 3 }, isEmpty: false },
          },
        }));
        log("send selection_changed (3 lines)");
      }, delayMs);
    }

    if (msg.id === undefined || msg.id === null) return;
    let reply;
    if (msg.method === "initialize") {
      reply = { result: {
        protocolVersion: msg.params?.protocolVersion ?? "2025-03-26",
        capabilities: { tools: {} },
        serverInfo: { name: "repro-ide", version: "0.0.1" },
      } };
    } else if (msg.method === "tools/list") {
      reply = { result: { tools: [] } };
    } else {
      reply = { error: { code: -32601, message: "Method not found" } };
    }
    ws.send(JSON.stringify({ jsonrpc: "2.0", id: msg.id, ...reply }));
    log(`send response id=${msg.id}`);
  });
});

</details>

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.288 (Claude Code)

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Other

Additional Information

Measured with the repro server on macOS 26.6.2, M1 Pro, Claude Code 2.1.288. Delay is counted from receiving ide_connected; "shown" means the indicator appeared within 5 s.

| Delay | claude --ide | /ide in a running session |
|--------|------------------|-----------------------------|
| 0 ms | lost, 4 of 4 | lost, 2 of 2 |
| 10 ms | lost, 3 of 3 | shown, 1 of 1 |
| 25 ms | shown, 1 of 1 | shown, 1 of 1 |
| 500 ms | shown, 3 of 3 | shown, 1 of 1 |

A real integration (the Obsidian plugin) gave the same boundary on this machine. On Windows 10 with Claude Code 2.1.282, the window reached about 400 ms (report).

Related: #95859, where at_mentioned and selection_changed are dropped while the agents view has focus. The trigger is different (focus, not connection timing), the symptom is the same silent drop.

View original on GitHub ↗