MHSanaei/3x-ui · error · errRemoteResponseTooLarge

%s %s: %w (content-length %d, cap %d)

Error message

%s %s: %w (content-length %d, cap %d)

What it means

Returned by Remote.do when the response's declared Content-Length already exceeds maxRemoteResponseBytes, wrapping errRemoteResponseTooLarge. This is the fast-fail path: it refuses to stream a body the node honestly declared as oversized. It protects the master's memory from a node (or something impersonating one) that returns a gigantic payload.

Source

Thrown at internal/web/runtime/remote.go:273

	// Validate status before reading a success payload: a non-OK response's
	// body is never used beyond a short diagnostic, so don't let a node force us
	// to buffer a large body just to return an HTTP error.
	if resp.StatusCode != http.StatusOK {
		snippet, _ := io.ReadAll(io.LimitReader(resp.Body, errBodyDiagBytes))
		if msg := bytes.TrimSpace(snippet); len(msg) > 0 {
			// %q quotes/escapes the untrusted node body so control characters or
			// newlines in it can't garble or inject into the error/log output.
			return nil, fmt.Errorf("%s %s: HTTP %d: %q", method, path, resp.StatusCode, msg)
		}
		return nil, fmt.Errorf("%s %s: HTTP %d", method, path, resp.StatusCode)
	}

	// Fast-fail on an honestly-declared oversize body; the LimitReader below is
	// the real guard since Content-Length is untrusted, may be absent, or is -1
	// under transparent decompression.
	if resp.ContentLength > maxRemoteResponseBytes {
		return nil, fmt.Errorf("%s %s: %w (content-length %d, cap %d)", method, path, errRemoteResponseTooLarge, resp.ContentLength, maxRemoteResponseBytes)
	}

	raw, err := readCappedBody(resp.Body, maxRemoteResponseBytes)
	if err != nil {
		if errors.Is(err, errRemoteResponseTooLarge) {
			return nil, fmt.Errorf("%s %s: %w (cap %d bytes)", method, path, err, maxRemoteResponseBytes)
		}
		return nil, fmt.Errorf("read body: %w", err)
	}

	var env envelope
	if err := json.Unmarshal(raw, &env); err != nil {
		return nil, fmt.Errorf("decode envelope: %w", err)
	}
	if !env.Success {
		return &env, &remoteAPIError{msg: env.Msg}
	}
	return &env, nil

View on GitHub (pinned to ad32144c42)

Solutions

  1. Check the reported content-length vs cap: if it is a legitimate inbound-list response, shrink the payload (fewer inbounds per node, trim client remarks) or raise maxRemoteResponseBytes in remote.go after measuring real sizes.
  2. curl -sI the same endpoint on the node to see what the big body actually is — if it is not JSON, the master is hitting the wrong route.
  3. Verify master and node versions match so list endpoints return the same compact shape.
  4. Do not wrap or gzip-transform the response in a way that inflates Content-Length (proxy double-encoding).

Example fix

// before: node returns 40MB inbound list
// err: GET panel/api/inbounds/list: remote response too large (content-length 41943040, cap 8388608)

// after: split clients across more nodes/inbounds, or in remote.go raise the constant after review
// const maxRemoteResponseBytes = 64 << 20
Defensive patterns

Strategy: validation

Validate before calling

// Estimate list size before fetching
if nodeInboundCount > safeInboundBudget { // e.g. thousands of clients per node
    return errors.New("node payload likely exceeds master cap; split inbounds across nodes")
}

Type guard

func isResponseTooLarge(err error) bool {
    return err != nil && strings.Contains(err.Error(), "remote response too large")
}

Try / catch

if err := remote.ListInboundOptions(ctx); err != nil {
    if isResponseTooLarge(err) {
        // capacity decision, not a retry: shard or raise cap deliberately
        return shardNodeInbounds(nodeID)
    }
    return err
}

Prevention

When it happens

Trigger: An RPC whose response legitimately grew past the cap — e.g. panel/api/inbounds/list on a node with an enormous number of inbounds/clients — or a node endpoint replying with a huge non-JSON payload (log dump, HTML page) because of a version mismatch or wrong route.

Common situations: Node with thousands of inbounds or very large settings JSON; master pointed at a URL that returns something other than the expected API (misconfigured address returning a big static file); a runaway handler on the node serializing internal state.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/eeeb76abeb629574. Report an issue: GitHub.