ginuerzh/gost · error

resp.Status

Error message

resp.Status

What it means

In the http2 connector, after sending an HTTP/2 CONNECT request, any response status other than 200 causes the response body to be closed and an error carrying the raw HTTP status line (resp.Status, e.g. '403 Forbidden') to be returned. The library throws this because a non-200 means the proxy/tunnel refused to establish the HTTP/2 tunnel, so no usable connection exists.

Source

Thrown at http2.go:101

			"Basic "+base64.StdEncoding.EncodeToString([]byte(u+":"+p)))
	}
	if Debug {
		dump, _ := httputil.DumpRequest(req, false)
		log.Log("[http2]", string(dump))
	}
	resp, err := cc.client.Do(req)
	if err != nil {
		cc.Close()
		return nil, err
	}
	if Debug {
		dump, _ := httputil.DumpResponse(resp, false)
		log.Log("[http2]", string(dump))
	}

	if resp.StatusCode != http.StatusOK {
		resp.Body.Close()
		return nil, errors.New(resp.Status)
	}
	hc := &http2Conn{
		r:      resp.Body,
		w:      pw,
		closed: make(chan struct{}),
	}

	hc.remoteAddr, _ = net.ResolveTCPAddr("tcp", address)
	hc.localAddr, _ = net.ResolveTCPAddr("tcp", cc.addr)

	return hc, nil
}

type http2Transporter struct {
	clients     map[string]*http.Client
	clientMutex sync.Mutex
	tlsConfig   *tls.Config
}

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Read the status text in the returned error to identify the cause (401/407 → auth, 403 → forbidden, 5xx → proxy/server problem)
  2. Supply proxy credentials (auth node options / Proxy-Authorization) if 401/407
  3. Verify the destination is allowed by the proxy's ACL, or use an allowed target
  4. Test the proxy directly (curl --http2-prior-knowledge -X CONNECT or equivalent) to confirm it supports HTTP/2 CONNECT tunneling

Example fix

// before
c, err := h2Connector.Connect(ctx, cc, "forbidden-host:443")
if err != nil { log.Fatal(err) } // '403 Forbidden' with no context
// after
c, err := h2Connector.Connect(ctx, cc, address)
if err != nil {
  log.Printf("http2 tunnel to %s rejected: %v", address, err) // status line reveals cause
  return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate proxy reachability/auth before tunneling
resp, err := httpclient.Get("https://" + proxyHost + "/")
if err == nil && (resp.StatusCode == 401 || resp.StatusCode == 407) {
    return nil, errors.New("proxy credentials missing or invalid")
}

Type guard

func isConnectRejected(err error) bool {
    // error text is the raw HTTP status line, e.g. '403 Forbidden'
    return err != nil && regexp.MustCompile(`^\d{3} `).MatchString(err.Error())
}

Try / catch

c, err := connector.Connect(ctx, cc, address)
if err != nil {
    if isConnectRejected(err) {
        switch {
        case strings.HasPrefix(err.Error(), "401"), strings.HasPrefix(err.Error(), "407"):
            return nil, fmt.Errorf("proxy auth required: %w", err)
        default:
            return nil, fmt.Errorf("tunnel to %s rejected: %w", address, err)
        }
    }
    return nil, err
}

Prevention

When it happens

Trigger: Dialing through an HTTP/2 proxy whose response to the CONNECT request is not 200 OK — auth rejected (401/407), target forbidden (403), target unreachable (404/502), rate limits (429), or server errors (500/502/503).

Common situations: Proxy requiring credentials that weren't supplied; proxy ACLs blocking the destination; the remote host rejecting CONNECT tunneling entirely; expired proxy sessions/tokens; misconfigured proxy upstream.

Related errors


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