v2fly/v2ray-core · error
no inbound metadata
Error message
no inbound metadata
What it means
This is a hard Go panic raised in the VLESS inbound's Process() right after the VLESS request header is decoded and accepted. The handler requires session.Inbound metadata in the context; that value is attached by the proxyman inbound worker (app/proxyman/inbound/worker.go, session.ContextWithInbound) when a connection arrives through a registered inbound. A nil result from session.InboundFromContext(ctx) means the proxy was invoked outside that pipeline, so it aborts the process.
Source
Thrown at proxy/vless/inbound/inbound.go:368
log.Record(&log.AccessMessage{
From: connection.RemoteAddr(),
To: "",
Status: log.AccessRejected,
Reason: err,
})
err = newError("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
}
return err
}
if err := connection.SetReadDeadline(time.Time{}); err != nil {
newError("unable to set back read deadline").Base(err).AtWarning().WriteToLog(sid)
}
newError("received request for ", request.Destination()).AtInfo().WriteToLog(sid)
inbound := session.InboundFromContext(ctx)
if inbound == nil {
panic("no inbound metadata")
}
inbound.User = request.User
responseAddons := &encoding.Addons{}
if request.Command != protocol.RequestCommandMux {
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: connection.RemoteAddr(),
To: request.Destination(),
Status: log.AccessAccepted,
Reason: "",
Email: request.User.Email,
})
}
sessionPolicy = h.policyManager.ForLevel(request.User.Level)
ctx, cancel := context.WithCancel(ctx)
timer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)View on GitHub (pinned to db12914161)
Solutions
- Make sure the VLESS inbound is reached through a configured inbound handler so proxyman's worker stamps the context (see session.ContextWithInbound calls in app/proxyman/inbound/worker.go).
- If you must call Process() directly, attach inbound metadata yourself first: ctx = session.ContextWithInbound(ctx, &session.Inbound{Tag: ...}).
- Copy the established pattern from app/tun/handler_tcp.go:89 or app/reverse/bridge.go:105 when building custom entry points.
- Add a recover() guard in custom embedding layers and fail the single connection instead of crashing the process during bring-up of the new path.
Example fix
// before
ctx := context.WithValue(context.Background(), myKey, myVal)
err = s.vlessInbound.Process(ctx, link, connection) // panic: no inbound metadata
// after
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: "vless-in",
Source: net.DestinationFromAddr(connection.RemoteAddr()),
})
err = s.vlessInbound.Process(ctx, link, connection) Defensive patterns
Strategy: validation
Validate before calling
// ensure inbound metadata exists before invoking the VLESS inbound:
if session.InboundFromContext(ctx) == nil {
ctx = session.ContextWithInbound(ctx, &session.Inbound{
Tag: "vless-in",
Source: net.DestinationFromAddr(connection.RemoteAddr()),
})
}
err := vlessInbound.Process(ctx, link, connection) Type guard
func hasInboundMetadata(ctx context.Context) bool {
return session.InboundFromContext(ctx) != nil
} Try / catch
defer func() {
if r := recover(); r != nil {
log.Printf("vless inbound panicked (likely missing session.Inbound in ctx): %v\n%s", r, debug.Stack())
}
}()
err := vlessInbound.Process(ctx, link, connection) Prevention
- Run VLESS inbound traffic through a configured inbound handler; the proxyman worker is the only sanctioned producer of the inbound context.
- In tests, build the context with session.ContextWithInbound instead of context.Background().
- When adding new transports, lint/grep for proxy.Process call sites and require a nearby ContextWithInbound.
- Keep contexts as descendants of the worker ctx; avoid opaque context wrappers that do not delegate Value().
When it happens
Trigger: Calling vless inbound Process() with a context that was never passed through proxyman's worker (unit tests, custom dispatchers); a custom transport/stream dispatch that constructs its own ctx and calls the proxy directly; context cloning/replacement code between connection accept and Process() that loses the inbound value; calling the handler from a new code path (e.g. an API-triggered socket) without copying the pattern used in app/tun/handler_tcp.go (which does set session.Inbound).
Common situations: Developers writing handler tests with context.Background(); embedding the VLESS inbound into a custom server that accepts raw TLS/TCP connections itself; forks that add alternative listeners (systemd socket activation, TUN, gVisor netstack) and forget the session.ContextWithInbound call; refactors that wrap the context with a fresh non-Derived context.
Related errors
AI-assisted analysis of v2fly/v2ray-core@db12914161 (2026-08-15).
Data as JSON: /api/errors/a1069c0c2e41a84a.
Report an issue: GitHub.