{"record":{"id":"378ada3dd1d8c23d","repo":"micro/go-micro","slug":"failed-to-read-request-w","errorCode":null,"errorMessage":"failed to read request: %w","messagePattern":"failed to read request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gateway/mcp/stdio.go","lineNumber":95,"sourceCode":"// Serve starts the stdio transport and processes JSON-RPC requests\nfunc (t *StdioTransport) Serve() error {\n\tt.server.opts.Logger.Printf(\"[mcp] MCP server started (stdio transport)\")\n\n\t// Read and process requests from stdin\n\tfor {\n\t\tselect {\n\t\tcase <-t.ctx.Done():\n\t\t\treturn nil\n\t\tdefault:\n\t\t}\n\n\t\t// Read one line (JSON-RPC request)\n\t\tline, err := t.reader.ReadBytes('\\n')\n\t\tif err != nil {\n\t\t\tif err == io.EOF {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to read request: %w\", err)\n\t\t}\n\n\t\t// Parse JSON-RPC request\n\t\tvar req JSONRPCRequest\n\t\tif err := json.Unmarshal(line, &req); err != nil {\n\t\t\tt.sendError(nil, ParseError, \"Parse error\", err.Error())\n\t\t\tcontinue\n\t\t}\n\n\t\t// Validate JSON-RPC version\n\t\tif req.JSONRPC != \"2.0\" {\n\t\t\tt.sendError(req.ID, InvalidRequest, \"Invalid request\", \"jsonrpc must be '2.0'\")\n\t\t\tcontinue\n\t\t}\n\n\t\t// Handle request\n\t\tgo t.handleRequest(&req)\n\t}","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/gateway/mcp/stdio.go#L77-L113","documentation":"The stdio transport reads newline-delimited JSON-RPC requests from stdin. ReadBytes returns nil for a clean EOF (client closed stdin) but any other read error — broken pipe on stdin, I/O error from the attached process — is wrapped as \"failed to read request: %w\" and returned from Serve, terminating the transport loop.","triggerScenarios":"StdioTransport.Serve() encounters a non-EOF read error on the stdin reader: the parent process's stdin pipe breaks, the fd is closed unexpectedly, or an OS-level I/O error occurs while blocking on ReadBytes('\\n').","commonSituations":"Parent process (e.g. an MCP client like an editor/agent) crashes or closes the pipe abruptly; running the binary where stdin is a closed/invalid fd; container runtime killing the input stream; malformed pipe handling in a supervisor that restarts the child mid-read.","solutions":["Inspect the wrapped %w error to identify the OS-level cause (e.g. 'file already closed', EPIPE).","Ensure the parent process keeps the stdin pipe open for the lifetime of the MCP server and closes it cleanly to signal shutdown (clean EOF returns nil).","Check that your process supervisor isn't closing or re-binding stdin while the server runs.","Return/handle the error in the caller of Serve and restart the transport if the failure is transient."],"exampleFix":"// before\nif err := transport.Serve(); err != nil {\n    log.Printf(\"mcp: %v\", err) // failed to read request: file already closed\n}\n// after\nif err := transport.Serve(); err != nil {\n    if errors.Is(err, os.ErrClosed) {\n        log.Printf(\"mcp: stdin closed unexpectedly, restarting\")\n        go func() { _ = transport.Serve() }()\n    } else {\n        log.Printf(\"mcp: fatal: %v\", err)\n    }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := transport.Serve(); err != nil {\n    if errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, os.ErrClosed) || errors.Is(err, syscall.EPIPE) {\n        // stdin stream broken: log, reconnect from parent, or restart transport\n    } else {\n        return err\n    }\n}","preventionTips":["Keep the parent process's stdin pipe open for the server's lifetime; close it cleanly for shutdown (EOF returns nil).","Test stdio transports under real parent processes (editors/agents), not just with inherited terminal stdin.","In containers, verify the entrypoint doesn't detach or close stdin.","Supervise Serve and restart on transient I/O errors."],"tags":["mcp","stdio","json-rpc","io"],"backgroundTag":"broken-pipe","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}