{"record":{"id":"5ac3d97b731e1047","repo":"XTLS/Xray-core","slug":"target-not-specified-5ac3d9","errorCode":null,"errorMessage":"target not specified","messagePattern":"target not specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/trojan/client.go","lineNumber":52,"sourceCode":"\tserver, err := protocol.NewServerSpecFromPB(config.Server)\n\tif err != nil {\n\t\treturn nil, errors.New(\"failed to get server spec\").Base(err)\n\t}\n\n\tv := core.MustFromContext(ctx)\n\tclient := &Client{\n\t\tserver:        server,\n\t\tpolicyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),\n\t}\n\treturn client, nil\n}\n\n// Process implements OutboundHandler.Process().\nfunc (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {\n\toutbounds := session.OutboundsFromContext(ctx)\n\tob := outbounds[len(outbounds)-1]\n\tif !ob.Target.IsValid() {\n\t\treturn errors.New(\"target not specified\")\n\t}\n\tob.Name = \"trojan\"\n\tob.CanSpliceCopy = 3\n\tdestination := ob.Target\n\tnetwork := destination.Network\n\n\tserver := c.server\n\tvar conn stat.Connection\n\n\terr := retry.ExponentialBackoff(5, 100).On(func() error {\n\t\trawConn, err := dialer.Dial(ctx, server.Destination)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tconn = rawConn\n\t\treturn nil\n\t})","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/trojan/client.go#L34-L70","documentation":"Thrown by the trojan client's Process when the latest outbound in the session context has no valid Target. Every proxied request must carry a destination; the trojan client dials that destination through the trojan server, so an empty target cannot proceed.","triggerScenarios":"Process invoked on a link whose session lacks a dispatcher-assigned destination — e.g. an inbound that forgot to set the target, a direct API call to the outbound handler, or internal requests (DNS over the outbound) missing a target.","commonSituations":"Custom embedding code dispatching to the trojan outbound without setting outbound.Target; a routing chain bug that strips the target; version skew in session plumbing after upgrading core.","solutions":["Ensure the caller (inbound/dispatcher) sets the destination before dispatch: outbound.Target = net.TCPDestination(addr, port).","If embedding, build the session outbound with a valid Target before calling Process.","Update the fork/launcher to the core version whose Process signature expects Target on the last outbound."],"exampleFix":"// embedding, before\nctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{}})\n\n// after\nctx = session.ContextWithOutbounds(ctx, []*session.Outbound{{\n\tTarget: net.TCPDestination(net.ParseAddress(\"1.2.3.4\"), 80),\n}})","handlingStrategy":"validation","validationCode":"if !ob.Target.IsValid() {\n\treturn errors.New(\"refusing to dispatch: no destination set on outbound\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set outbound.Target before dispatching to any outbound handler.","In tests, construct sessions with explicit destinations.","Freeze on a pinned core version when embedding to avoid Target API drift."],"tags":["trojan","outbound","session","target","embedding"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}