ginuerzh/gost · error

status %d

Error message

status %d

What it means

In the gost relay client path, relayConn.Read (relay.go:288) reads the server's relay response header once and, if the returned status is not relay.StatusOK (0), surfaces "status %d" with the numeric status code. It means the relay server accepted the connection but rejected the tunnel request instead of establishing the data channel.

Source

Thrown at relay.go:289

	headerSent bool
}

func (c *relayConn) Read(b []byte) (n int, err error) {
	c.once.Do(func() {
		if c.isServer {
			return
		}
		resp := new(relay.Response)
		_, err = resp.ReadFrom(c.Conn)
		if err != nil {
			return
		}
		if resp.Version != relay.Version1 {
			err = relay.ErrBadVersion
			return
		}
		if resp.Status != relay.StatusOK {
			err = fmt.Errorf("status %d", resp.Status)
			return
		}
	})

	if err != nil {
		log.Logf("[relay] %s <- %s: %s", c.Conn.LocalAddr(), c.Conn.RemoteAddr(), err)
		return
	}

	if !c.udp {
		return c.Conn.Read(b)
	}
	var bb [2]byte
	_, err = io.ReadFull(c.Conn, bb[:])
	if err != nil {
		return
	}
	dlen := int(binary.BigEndian.Uint16(bb[:]))

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Check the numeric status in the message against the relay protocol status codes to identify the exact rejection (e.g. unauthorized vs forbidden)
  2. Verify relay node credentials (user/password) in the gost config match the upstream relay server's auth config
  3. Confirm the upstream address is actually a gost relay endpoint speaking relay protocol Version1, not an HTTP/SOCKS server
  4. Inspect the remote relay server logs for the corresponding rejection reason and update the local node config accordingly

Example fix

// before
nodes = relay://user:wrongpass@relay.example.com:8421
// after
nodes = relay://user:correctpass@relay.example.com:8421
Defensive patterns

Strategy: try-catch

Validate before calling

// before dialing, verify the relay node has credentials that match the server
if node.Auth == nil {
    return errors.New("relay node requires auth credentials matching the server")
}

Type guard

func isRelayStatusError(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "status ")
}

Try / catch

conn, err := client.Dial(addr)
if err != nil {
    if isRelayStatusError(err) {
        code := strings.TrimPrefix(err.Error(), "status ")
        log.Printf("relay server rejected request with status %s; check auth/config", code)
        return err // server-side rejection, not transient — don't retry blindly
    }
    return retry(err)
}

Prevention

When it happens

Trigger: Connecting through a gost relay node whose server replies with a non-zero relay response status — e.g. authentication rejected by the remote relay, the remote node refusing the forward request, or a mismatch where the peer answers with an error status.

Common situations: Chained gost proxies where the upstream relay requires different credentials, the upstream address is served by a non-relay service, or relay protocol incompatibilities (the sibling ErrBadVersion check is at relay.go:284).

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/07d6903c22a69313. Report an issue: GitHub.