{"record":{"id":"a1069c0c2e41a84a","repo":"v2fly/v2ray-core","slug":"no-inbound-metadata-a1069c","errorCode":null,"errorMessage":"no inbound metadata","messagePattern":"no inbound metadata","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/vless/inbound/inbound.go","lineNumber":368,"sourceCode":"\t\t\tlog.Record(&log.AccessMessage{\n\t\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\t\tTo:     \"\",\n\t\t\t\tStatus: log.AccessRejected,\n\t\t\t\tReason: err,\n\t\t\t})\n\t\t\terr = newError(\"invalid request from \", connection.RemoteAddr()).Base(err).AtInfo()\n\t\t}\n\t\treturn err\n\t}\n\n\tif err := connection.SetReadDeadline(time.Time{}); err != nil {\n\t\tnewError(\"unable to set back read deadline\").Base(err).AtWarning().WriteToLog(sid)\n\t}\n\tnewError(\"received request for \", request.Destination()).AtInfo().WriteToLog(sid)\n\n\tinbound := session.InboundFromContext(ctx)\n\tif inbound == nil {\n\t\tpanic(\"no inbound metadata\")\n\t}\n\tinbound.User = request.User\n\n\tresponseAddons := &encoding.Addons{}\n\n\tif request.Command != protocol.RequestCommandMux {\n\t\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\t\tFrom:   connection.RemoteAddr(),\n\t\t\tTo:     request.Destination(),\n\t\t\tStatus: log.AccessAccepted,\n\t\t\tReason: \"\",\n\t\t\tEmail:  request.User.Email,\n\t\t})\n\t}\n\n\tsessionPolicy = h.policyManager.ForLevel(request.User.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, cancel, sessionPolicy.Timeouts.ConnectionIdle)","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/v2fly/v2ray-core/blob/db1291416195df07b287d79d8b9afe451c186c33/proxy/vless/inbound/inbound.go#L350-L386","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nctx := context.WithValue(context.Background(), myKey, myVal)\nerr = s.vlessInbound.Process(ctx, link, connection) // panic: no inbound metadata\n\n// after\nctx = session.ContextWithInbound(ctx, &session.Inbound{\n    Tag:    \"vless-in\",\n    Source: net.DestinationFromAddr(connection.RemoteAddr()),\n})\nerr = s.vlessInbound.Process(ctx, link, connection)","handlingStrategy":"validation","validationCode":"// ensure inbound metadata exists before invoking the VLESS inbound:\nif session.InboundFromContext(ctx) == nil {\n    ctx = session.ContextWithInbound(ctx, &session.Inbound{\n        Tag:    \"vless-in\",\n        Source: net.DestinationFromAddr(connection.RemoteAddr()),\n    })\n}\nerr := vlessInbound.Process(ctx, link, connection)","typeGuard":"func hasInboundMetadata(ctx context.Context) bool {\n    return session.InboundFromContext(ctx) != nil\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        log.Printf(\"vless inbound panicked (likely missing session.Inbound in ctx): %v\\n%s\", r, debug.Stack())\n    }\n}()\nerr := vlessInbound.Process(ctx, link, connection)","preventionTips":["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()."],"tags":["vless","inbound","context","panic","session","integration"],"backgroundTag":null,"analyzedSha":"db1291416195df07b287d79d8b9afe451c186c33","analyzedAt":"2026-08-15T14:51:20.977Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}