{"record":{"id":"18b762f4acaf509c","repo":"chatboxai/chatbox","slug":"failed-to-start-server-server-status-state","errorCode":null,"errorMessage":"Failed to start server: ${server.status.state}","messagePattern":"Failed to start server: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/components/settings/mcp/ConfigModal.tsx","lineNumber":85,"sourceCode":"\n  const testConnection = async () => {\n    if (formRef.current && !formRef.current.reportValidity()) {\n      return\n    }\n    const config = getConfigFromFormValues(form.getValues())\n    console.debug('Testing connection with config', config)\n    setTesting(true)\n    setTestingResult(null)\n    trackEvent('test_mcp_server_connection', { type: config.transport.type })\n    try {\n      const server = new MCPServer(config.transport)\n      testingAbortController.current = new AbortController()\n      await pTimeout(server.start(), {\n        milliseconds: 5 * 60_000,\n        signal: testingAbortController.current.signal,\n      })\n      if (server.status.state !== 'running') {\n        throw new Error(server.status.error || `Failed to start server: ${server.status.state}`)\n      }\n      const tools = await server.getAvailableTools()\n      setTestingResult({\n        config,\n        tools: Object.keys(tools).map((name) => ({ name, description: tools[name].description })),\n      })\n      await server.stop()\n    } catch (err) {\n      if (testingAbortController.current?.signal.aborted) {\n        return\n      }\n      setTestingResult({ config, error: err as Error, tools: [] })\n    } finally {\n      setTesting(false)\n    }\n  }\n\n  const handleSubmit = (values: typeof form.values) => {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/components/settings/mcp/ConfigModal.tsx#L67-L103","documentation":"Thrown in ConfigModal.testConnection (src/renderer/components/settings/mcp/ConfigModal.tsx:85) during the MCP server connection test. After `await pTimeout(server.start(), { milliseconds: 5min, signal })`, if server.status.state is not 'running', it throws server.status.error (if present) else this template. This branch is reached because MCPServer.start() catches its own transport errors and parks in state 'idle' with an error message instead of rethrowing, so the throw here is the normal failure-reporting path: state is typically 'idle' and server.status.error carries the real cause (which is preferred when non-empty).","triggerScenarios":"new MCPServer(config.transport).start() resolves without throwing but leaves state !== 'running' (i.e. 'idle' with error). Concrete causes: stdio transport where the command does not exist (ENOENT), command exits/crashes, missing args/env; http/sse transport with wrong URL, auth failure, 405/401 handshake, or both Streamable HTTP and legacy SSE fallback failing; start() aborted via the AbortController. The pTimeout itself throws a different error (TimeoutError) that is caught separately at line 93.","commonSituations":"User enters an MCP server config and clicks Test: mistyped command path (npx vs npx.exe, missing binary), command not installed, wrong/missing API URL or token for a remote server, server endpoint does not speak Streamable HTTP or SSE, slow server exceeding the 5-minute timeout, or a stdio server that prints errors to stderr and exits.","solutions":["Read the full message: server.status.error is used when present and usually names the real cause (e.g. ENOENT, 'MCP SSE Transport Error: 405'). The ConfigModal already shows an ENOENT hint for stdio.","For stdio: verify the command is installed and on PATH in the runtime shell; test it in a terminal first (e.g. `npx -y <pkg>` or the absolute path).","For http/sse: verify the URL is reachable and returns 2xx; confirm auth headers/tokens; ensure the server implements Streamable HTTP or SSE.","Check the browser/runtime console: MCPServer logs 'mcp:client:start' / 'mcp:client:onUncaughtError' with the underlying error.","If the server is slow, note the 5-minute pTimeout ceiling; a timeout surfaces as a TimeoutError, not this message."],"exampleFix":"// before\nawait pTimeout(server.start(), { milliseconds: 5 * 60_000, signal })\nif (server.status.state !== 'running') {\n  throw new Error(server.status.error || `Failed to start server: ${server.status.state}`)\n}\n\n// after (surface the real cause, keep the generic fallback)\nawait pTimeout(server.start(), { milliseconds: 5 * 60_000, signal })\nif (server.status.state !== 'running') {\n  const reason = server.status.error || `Failed to start server: ${server.status.state}`\n  console.error('MCP test failed', { state: server.status.state, error: server.status.error })\n  throw new Error(reason)\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"// Narrow MCPServerStatus to extract the failure reason\nfunction mcpStartFailure(\n  s: { state: string; error?: string }\n): string | null {\n  return s.state === 'running' ? null : s.error || `Failed to start server: ${s.state}`\n}","tryCatchPattern":"// The test path already wraps this; mirror it for runtime starts\ntry {\n  await pTimeout(server.start(), { milliseconds: 5 * 60_000, signal })\n  if (server.status.state !== 'running') {\n    throw new Error(server.status.error || `Failed to start server: ${server.status.state}`)\n  }\n} catch (e) {\n  showMcpError((e as Error).message) // server.status.error usually carries the real cause\n} finally {\n  await server.stop().catch(() => {})\n}","preventionTips":["Test the stdio command in a real terminal before saving the MCP config.","For http/sse, curl the endpoint to confirm it speaks Streamable HTTP or SSE and returns 2xx.","Always stop the server in a finally block to avoid orphaned stdio processes.","Read the runtime console: MCPServer logs the underlying transport error at 'mcp:client:start'.","Respect the 5-minute pTimeout; a slow server will throw TimeoutError, not this status message."],"tags":["mcp","config","connection","stdio","transport"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}