claudecodeui icon indicating copy to clipboard operation
claudecodeui copied to clipboard

Bug: Web UI stuck on 'Thinking...' - Frontend sends wrong message type (v1.12.0)

Open terrylica opened this issue 1 month ago • 1 comments

Environment

  • claudecodeui version: 1.12.0 (installed via git clone from main branch)
  • Node.js version: v25.2.1
  • OS: macOS Darwin 24.6.0
  • Installation method: git clone + npm install + npm run build
  • @anthropic-ai/claude-agent-sdk version: 0.1.29

Description

When using the web UI to send a message to Claude, the interface shows "Thinking..." indefinitely and never receives a response. The WebSocket connection is established successfully, but chat messages from the frontend are not being processed by the server.

Root Cause Analysis

After extensive first-principles debugging, I identified the issue:

1. Backend SDK Integration Works ✅

Direct SDK test from the claudecodeui directory succeeds:

import { query } from './node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs';

const q = query({
  prompt: 'Say exactly: HELLO',
  options: { model: 'haiku', maxTurns: 1 }
});

for await (const msg of q) {
  console.log(msg.type); // system, assistant, result - all received correctly
}

2. WebSocket Connection Works ✅

Authentication and connection succeed:

[OK] WebSocket authenticated for user: terryli
[INFO] Chat WebSocket connected

3. Server Message Handler Expects claude-command

In server/index.js:716, the handler checks for type: 'claude-command':

ws.on('message', async (message) => {
    const data = JSON.parse(message);

    if (data.type === 'claude-command') {
        // This is the only path that calls queryClaudeSDK()
        await queryClaudeSDK(data.command, data.options, ws);
    } else if (data.type === 'cursor-command') {
        // ...
    }
    // No else clause - unknown message types are silently ignored
});

4. Frontend Message Type Mismatch ❌

When I manually send type: 'claude-command' via WebSocket, everything works:

ws.send(JSON.stringify({
  type: 'claude-command',  // <-- This works
  command: 'Say hello',
  options: { cwd: '/path/to/project' }
}));

// Response received:
// [WS] session-created
// [WS] claude-response (system)
// [WS] claude-response (assistant)
// [WS] claude-response (result)
// [WS] claude-complete

But when using the actual web UI, no server-side logs appear for message processing - only projects_updated broadcast events. This indicates the frontend is sending a message type that doesn't match any handler case.

Steps to Reproduce

  1. Install claudecodeui v1.12.0 via git clone
  2. Run npm install and npm run build
  3. Start server with node server/index.js
  4. Open http://localhost:3001 in browser
  5. Login and select a project
  6. Type any message and press Enter
  7. Observed: "Thinking..." spinner shows indefinitely
  8. Expected: Claude response appears

Workaround

None currently. The web UI is non-functional for sending messages.

Validation Script

I created a test script that confirms the backend works when the correct message format is used:

// test-websocket.mjs
import WebSocket from 'ws';

const loginResponse = await fetch('http://localhost:3001/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ username: 'USER', password: 'PASS' })
});
const { token } = await loginResponse.json();

const ws = new WebSocket(`ws://localhost:3001/ws?token=${token}`);

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'claude-command',  // Must be this exact type
    command: 'Say hello',
    options: { cwd: '/path/to/project' }
  }));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data.toString());
  console.log('Received:', msg.type);
  if (msg.type === 'claude-complete') {
    console.log('SUCCESS - Backend works!');
    ws.close();
  }
});

Suggested Fix

Investigate what message type the frontend is actually sending. Look in the React frontend code (likely in src/ or dist/) for WebSocket send calls and ensure they use type: 'claude-command' with the expected payload structure:

{
  type: 'claude-command',
  command: string,        // The user's message
  options: {
    cwd: string,          // Project path
    sessionId?: string,   // For resuming sessions
    projectPath?: string,
    // ... other options
  }
}

Additional Context

  • The handleChatConnection function in server/index.js silently ignores message types that don't match known handlers
  • Adding a catch-all else clause with logging would help debug similar issues:
    } else {
      console.log('[WARN] Unknown message type:', data.type, data);
    }
    

terrylica avatar Nov 26 '25 05:11 terrylica

I also encounter this problem. it's always stuck on "Thinking...". If I switch to shell i found below situation:

ybalbert001 avatar Nov 26 '25 08:11 ybalbert001