XTLS/Xray-core · error · errors.Error

missing inbound or outbound metadata from context

Error message

missing inbound or outbound metadata from context

What it means

fillRequestHeader needs inbound.Source and the last outbound's Target to template headers (e.g. X-Real-IP style values). If session.InboundFromContext returns nil or the outbounds slice's tail is nil, header rendering cannot proceed and this error is returned (then wrapped as "failed to fill out header" by the caller).

Source

Thrown at proxy/http/client.go:177

	if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
		return errors.New("connection ends").Base(err)
	}

	return nil
}

// fillRequestHeader will fill out the template of the headers
func fillRequestHeader(ctx context.Context, header []*Header) ([]*Header, error) {
	if len(header) == 0 {
		return header, nil
	}

	inbound := session.InboundFromContext(ctx)
	outbounds := session.OutboundsFromContext(ctx)
	ob := outbounds[len(outbounds)-1]

	if inbound == nil || ob == nil {
		return nil, errors.New("missing inbound or outbound metadata from context")
	}

	data := struct {
		Source net.Destination
		Target net.Destination
	}{
		Source: inbound.Source,
		Target: ob.Target,
	}

	filled := make([]*Header, len(header))
	for i, h := range header {
		tmpl, err := template.New(h.Key).Parse(h.Value)
		if err != nil {
			return nil, err
		}
		var buf bytes.Buffer

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Only configure settings.headers when all traffic through this outbound comes from standard inbounds that attach session data
  2. In tests, inject session.ContextWithInbound/ContextWithOutbounds before calling Process
  3. Remove headers if the upstream proxy does not require them

Example fix

```go
ctx = session.ContextWithInbound(ctx, &session.Inbound{ Source: src })
ctx = session.ContextWithOutbounds(ctx, &session.Outbound{ Target: dest })
// then Process
```
Defensive patterns

Strategy: validation

Validate before calling

```go
ctx = session.ContextWithInbound(ctx, &session.Inbound{Source: src})
ctx = session.ContextWithOutbounds(ctx, &session.Outbound{Target: target})
// only now call Process with headers enabled
```

Type guard

```go
func hasSessionMetadata(ctx context.Context) bool {
    in := session.InboundFromContext(ctx)
    obs := session.OutboundsFromContext(ctx)
    return in != nil && len(obs) > 0 && obs[len(obs)-1] != nil
}
```

Prevention

When it happens

Trigger: settings.headers[] is non-empty AND the session context lacks inbound metadata — e.g. synthetic contexts built by tests or outbounds invoked outside a normal dispatcher flow; or an empty outbounds slice making outbounds[len-1] panic-adjacent/nil.

Common situations: Unit tests invoking Process with a bare context; custom dispatchers that strip session metadata; headers configured globally but traffic originating from unusual inbounds.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/4d1933b36e273cfb. Report an issue: GitHub.