openimsdk/open-im-server · warning

error (dynamic message passed to http.Error)

Error message

error (dynamic message passed to http.Error)

What it means

ErrReturn is a thin wrapper around net/http's http.Error, writing an error string and HTTP status code to the WebSocket upgrade response writer. Because the message is a dynamic string passed straight through, any caller-supplied text is emitted as the HTTP response body. This error entry flags that dynamic message: the client sees whatever string the gateway hands to ErrReturn (e.g. invalid token, bad upgrade request, rate limit).

Source

Thrown at internal/msggateway/context.go:193

		info.SDKType = GoSDK
	case GoSDK, JsSDK:
	default:
		return servererrs.ErrConnArgsErr.WrapMsg("sdkType is invalid")
	}
	c.info = info
	return nil
}

func (c *UserConnContext) GetRemoteAddr() string {
	return c.RemoteAddr
}

func (c *UserConnContext) SetHeader(key, value string) {
	c.RespWriter.Header().Set(key, value)
}

func (c *UserConnContext) ErrReturn(error string, code int) {
	http.Error(c.RespWriter, error, code)
}

func (c *UserConnContext) GetConnID() string {
	return c.ConnID
}

func (c *UserConnContext) GetUserID() string {
	if c == nil || c.info == nil {
		return ""
	}
	return c.info.UserID
}

func (c *UserConnContext) GetPlatformID() int {
	if c == nil || c.info == nil {
		return 0
	}
	return c.info.PlatformID

View on GitHub (pinned to 175a7bb067)

Solutions

  1. Inspect the HTTP response body/status returned on the WS handshake — the dynamic string is the gateway's rejection reason; fix the underlying condition it reports (usually token or params).
  2. In the gateway, replace free-form strings with typed, constant error messages so clients can match them reliably.
  3. Ensure ErrReturn is only called with non-sensitive, user-safe messages; log full details server-side instead.
  4. Client-side: handle non-101 handshake responses explicitly (check response status/code) rather than treating any failure as a network error.

Example fix

// before
c.ErrReturn(fmt.Sprintf("token invalid: %v", err), http.StatusUnauthorized)

// after
c.ErrReturn("token invalid", http.StatusUnauthorized) // details logged server-side
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side, before treating handshake as success
resp, err := dialer.DialContext(ctx, wsURL, hdr)
if err != nil {
	if resp != nil && resp.StatusCode != http.StatusSwitchingProtocols {
		body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
		return fmt.Errorf("gateway rejected handshake (%d): %s", resp.StatusCode, body)
	}
	return err
}

Type guard

func isGatewayRejection(err error) bool {
	var he *websocket.HTTPError // or check resp status from your WS lib
	return errors.As(err, &he) && he.StatusCode >= 400
}

Try / catch

conn, resp, err := dialer.Dial(wsURL, hdr)
if err != nil {
	if resp != nil {
		switch resp.StatusCode {
		case http.StatusUnauthorized:
			// refresh token and retry once
		case http.StatusForbidden:
			// origin/permission problem — do not retry
		default:
			log.Printf("gateway error: %s", resp.Status)
		}
	}
	return err
}

Prevention

When it happens

Trigger: Any code path in the message gateway that calls UserConnContext.ErrReturn(msg, code) before or instead of upgrading the WebSocket connection — e.g. failed authentication/token validation, missing query parameters, rejected origin, or internal errors during the HTTP handshake phase.

Common situations: A client hits the WebSocket endpoint with an expired/invalid token and receives a plain-text error body instead of a WS connection; proxy or CORS misconfig causes the handshake to be rejected; gateway version changes the error strings so client-side parsers break; developers accidentally send sensitive internals via this dynamic message.

Related errors


AI-assisted analysis of openimsdk/open-im-server@175a7bb067 (2026-09-04). Data as JSON: /api/errors/947b426408a69308. Report an issue: GitHub.