{"record":{"id":"4a573d0b27a91021","repo":"microsoft/typescript-go","slug":"32600-4a573d","errorCode":"-32600","errorMessage":"%w: %w","messagePattern":"%w: %w","errorType":"error_code","errorClass":"ErrorCode","httpStatus":null,"severity":"error","filePath":"internal/lsp/server.go","lineNumber":137,"sourceCode":"\nfunc (e *messageMarshalError) Error() string { return \"failed to marshal message: \" + e.err.Error() }\n\nfunc (e *messageMarshalError) Unwrap() []error {\n\treturn []error{lsproto.ErrorCodeInternalError, e.err}\n}\n\nfunc (r *lspReader) Read() (*lsproto.Message, error) {\n\tdata, err := r.r.Read()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq := &lsproto.Message{}\n\tif err := json.Unmarshal(data, req); err != nil {\n\t\tif errors.Is(err, lsproto.ErrorCodeInvalidParams) {\n\t\t\treturn req, fmt.Errorf(\"%w: %w\", lsproto.ErrorCodeInvalidParams, err)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%w: %w\", lsproto.ErrorCodeInvalidRequest, err)\n\t}\n\n\treturn req, nil\n}\n\nfunc ToReader(r io.Reader) Reader {\n\treturn &lspReader{r: lsproto.NewBaseReader(r)}\n}\n\nfunc (w *lspWriter) Write(msg *lsproto.Message) error {\n\tdata, err := json.Marshal(msg)\n\tif err != nil {\n\t\treturn &messageMarshalError{err: err}\n\t}\n\treturn w.w.Write(data)\n}\n\nfunc ToWriter(w io.Writer) Writer {","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/lsp/server.go#L119-L155","documentation":"In lspReader.Read (server.go:133-137), the raw JSON-RPC message itself failed to unmarshal into lsproto.Message — malformed frame JSON, missing protocol-required members (jsonrpc/method), wrong top-level kinds — and the error does not classify as InvalidParams, so it is wrapped with ErrorCodeInvalidRequest (-32600). Unlike the -32602 path, the message is returned as nil: the frame is unidentifiable and only a generic error response (if the id could be recovered) is possible.","triggerScenarios":"Sending a JSON-RPC frame that is an array (batch, unsupported shape here), a frame missing \"method\", a frame where \"id\" is an object, or invalid JSON bytes from a misframed Content-Length stream; any decode failure in Message.UnmarshalJSON outside the params stage.","commonSituations":"Broken Content-Length framing (length mismatch truncating JSON); clients sending batch requests; proxies inserting BOM or log lines into the stream; version skew where clients assume permissive base-protocol parsing.","solutions":["Log the raw frame bytes and validate them with an independent JSON-RPC parser; fix framing (exact Content-Length byte count, UTF-8 no BOM).","Ensure single messages only — no batch arrays — and that every request/notification carries jsonrpc and method.","If a specific required member is rejected, compare against the JSON-RPC 2.0 shape lsproto.Message enforces (union of request/notification/response with strict kinds).","For proxies, pass the byte stream through unmodified and never interleave stdout writes."],"exampleFix":"// before: batch frame\n[{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"shutdown\"}]\n// after: single frame\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"shutdown\"}","handlingStrategy":"try-catch","validationCode":"// sender-side: validate the frame is a single, well-formed JSON-RPC message\nvar probe any\nif err := json.Unmarshal(frame, &probe); err != nil {\n    return fmt.Errorf(\"bad frame JSON: %w\", err)\n}\nm, ok := probe.(map[string]any)\nif !ok || m[\"jsonrpc\"] != \"2.0\" {\n    return fmt.Errorf(\"frame must be a single JSON-RPC 2.0 object\")\n}","typeGuard":"func isSingleJsonRpcObject(frame []byte) bool {\n    var v any\n    if json.Unmarshal(frame, &v) != nil {\n        return false\n    }\n    m, ok := v.(map[string]any)\n    return ok && m[\"jsonrpc\"] == \"2.0\"\n}","tryCatchPattern":"if _, err := reader.Read(); err != nil {\n    if errors.Is(err, lsproto.ErrorCodeInvalidRequest) {\n        // recoverable: skip the malformed frame, optionally send -32600 if an id was parsed\n        continue\n    }\n    return err\n}","preventionTips":["Compute Content-Length in bytes (not runes) and never interleave other output on the message stream.","Send single messages only; batch arrays are rejected.","Keep proxies transparent — no BOM, no log lines inside the framing."],"tags":["lsp","jsonrpc","framing","protocol"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}