mastra-ai/mastra · error
Failed to create LSP process with proper stdio
Error message
Failed to create LSP process with proper stdio
What it means
After spawning, the LSP client requires the child process to expose both stdin and stdout for the JSON-RPC stream connection. If either stream is missing (null), initialize() throws 'Failed to create LSP process with proper stdio'. Without these streams, createMessageConnection cannot be built, so the client fails fast.
Source
Thrown at mastracode/sdk/src/lsp/client.ts:44
*/
async initialize(): Promise<void> {
const spawnResult = await this.serverInfo.spawn(this.workspaceRoot);
if (!spawnResult) {
throw new Error('Failed to spawn LSP server');
}
// Handle both ChildProcess and { process: ChildProcess, initialization? } formats
let initializationOptions: any = undefined;
if ('process' in spawnResult) {
this.process = spawnResult.process;
initializationOptions = spawnResult.initialization;
} else {
this.process = spawnResult;
}
if (!this.process.stdin || !this.process.stdout) {
throw new Error('Failed to create LSP process with proper stdio');
}
const reader = new StreamMessageReader(this.process.stdout);
const writer = new StreamMessageWriter(this.process.stdin);
this.connection = createMessageConnection(reader, writer);
// Handle connection errors (e.g., ERR_STREAM_DESTROYED during shutdown)
this.connection.onError(error => {
// Silently ignore stream destroyed errors during shutdown
const errorObj = error?.[0] as any;
if (errorObj?.code !== 'ERR_STREAM_DESTROYED') {
}
});
// Set up diagnostic listener before starting connection
this.connection.onNotification('textDocument/publishDiagnostics', (params: any) => {
if (params.diagnostics && params.diagnostics.length > 0) {View on GitHub (pinned to 75dd419e61)
Solutions
- Spawn the server with stdio configured to pipe stdin/stdout (e.g. stdio: ['pipe', 'pipe', 'pipe']).
- If the spawn result shape is { process, initialization }, ensure `process` is the actual ChildProcess with working streams.
- Add a pre-check in the spawn callback that returns the ChildProcess only when stdin/stdout are present.
- Catch this error during initialize() and log the spawn args to identify the misconfigured stdio option.
Example fix
// before
spawn(command, args, { stdio: 'ignore' }); // stdin/stdout null
// after
spawn(command, args, { stdio: ['pipe', 'pipe', 'pipe'] }); Defensive patterns
Strategy: validation
Validate before calling
import type { ChildProcess } from 'node:child_process';
function hasValidStdio(p: ChildProcess | null | undefined): p is ChildProcess & { stdin: NonNullable<ChildProcess['stdin']>; stdout: NonNullable<ChildProcess['stdout']> } {
return !!p && p.stdin != null && p.stdout != null;
}
// validate the result of spawn before handing it to LSPClient Type guard
function isSpawnableProcess(p: unknown): p is ChildProcess & { stdin: NodeJS.WritableStream; stdout: NodeJS.ReadableStream } {
const c = p as ChildProcess | undefined;
return !!c && typeof c.pid === 'number' && c.stdin != null && c.stdout != null;
} Try / catch
try {
await client.initialize();
} catch (e) {
if (e.message === 'Failed to create LSP process with proper stdio') {
throw new Error(`LSP server '${serverInfo.command}' must be spawned with piped stdin/stdout (stdio: 'pipe')`);
}
throw e;
} Prevention
- Always spawn LSP servers with stdio pipes for stdin/stdout ('pipe' or 'jsonrpc').
- In custom spawn implementations, return the ChildProcess only after confirming stdin/stdout exist.
- Avoid detached/ignore stdio modes for LSP server processes.
When it happens
Trigger: serverInfo.spawn returned a process-like object whose stdin/stdout are null — e.g. spawn created with stdio: 'ignore' or piped incorrectly, a custom spawn implementation returning an object without proper stdio streams, or the process exited immediately destroying streams before the check.
Common situations: Custom LSPServerInfo implementations using stdio options other than 'pipe'/'jsonrpc' for stdin/stdout; a server wrapper that detaches stdio; spawn options like detached:true with stdio 'ignore'.
Related errors
- Failed to spawn LSP server
- ThreadLockError(threadId, ownerPid)
- Process failed to spawn
- maxRetainedBytes must be a non-negative integer or Infinity
- ${this.constructor.name} does not support closing stdin
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/e9bbc7d42a5606a1.
Report an issue: GitHub.