{"record":{"id":"fa7d1cca62058a0a","repo":"router-for-me/CLIProxyAPI","slug":"wsrelay-unknown-error","errorCode":null,"errorMessage":"wsrelay: unknown error","messagePattern":"wsrelay: unknown error","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/wsrelay/http.go","lineNumber":237,"sourceCode":"\tif body, ok := payload[\"body\"].(string); ok {\n\t\tresp.Body = []byte(body)\n\t}\n\treturn resp\n}\n\nfunc decodeChunk(payload map[string]any) []byte {\n\tif payload == nil {\n\t\treturn nil\n\t}\n\tif data, ok := payload[\"data\"].(string); ok {\n\t\treturn []byte(data)\n\t}\n\treturn nil\n}\n\nfunc decodeError(payload map[string]any) error {\n\tif payload == nil {\n\t\treturn errors.New(\"wsrelay: unknown error\")\n\t}\n\tmessage, _ := payload[\"error\"].(string)\n\tstatus := 0\n\tif v, ok := payload[\"status\"].(float64); ok {\n\t\tstatus = int(v)\n\t}\n\tif message == \"\" {\n\t\tmessage = \"wsrelay: upstream error\"\n\t}\n\treturn fmt.Errorf(\"%s (status=%d)\", message, status)\n}\n","sourceCodeStart":219,"sourceCodeEnd":249,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/wsrelay/http.go#L219-L249","documentation":"decodeError in internal/wsrelay/http.go decodes an error frame (MessageTypeError) from the relay peer. If the payload map is nil — i.e. an error message arrived with no payload — it returns the generic `wsrelay: unknown error`. It is a defensive fallback for malformed/empty error frames; any real error should carry an `error` string and `status` number, which get formatted as `\"%s (status=%d)\"`.","triggerScenarios":"The relay peer sends a MessageTypeError frame with a nil or absent payload; version skew between proxy and relay peer where one side encodes errors differently; internal bug producing an error frame without payload.","commonSituations":"Mismatched CLIProxyAPI versions on either end of the wsrelay; a peer implementation that sends `{type:\"error\"}` with no details; debugging sessions where the actual cause is hidden by the generic message.","solutions":["Check both ends of the relay run the same CLIProxyAPI version so error payloads are always populated.","Capture the raw relay frames (wsrelay debug logging) to see what the peer actually sent before the nil payload.","Treat this error as a signal to inspect the peer's logs — the real failure happened on the other side and was not serialized.","Report upstream if the peer is a current CLIProxyAPI build, since error frames should always carry payload."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":"func isUnknownRelayError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"wsrelay: unknown error\")\n}","tryCatchPattern":"if isUnknownRelayError(err) {\n    // real cause lives on the peer: check peer logs; retry once in case of frame corruption\n    log.Warn(\"relay error frame had no payload; inspecting peer\")\n    err = retryOnce()\n}","preventionTips":["Pin both ends of the relay to the same CLIProxyAPI version.","Log raw relay frames in debug mode so empty error payloads are diagnosable.","Always populate error payloads when implementing a relay peer."],"tags":["wsrelay","error-handling","protocol"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}