{"record":{"id":"5c4afd0267e7b9e4","repo":"XTLS/Xray-core","slug":"user-account-is-not-valid-5c4afd","errorCode":null,"errorMessage":"user account is not valid","messagePattern":"user account is not valid","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/trojan/client.go","lineNumber":81,"sourceCode":"\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})\n\tif err != nil {\n\t\treturn errors.New(\"failed to find an available destination\").AtWarning().Base(err)\n\t}\n\terrors.LogInfo(ctx, \"tunneling request to \", destination, \" via \", server.Destination.NetAddr())\n\n\tdefer conn.Close()\n\n\tuser := server.User\n\taccount, ok := user.Account.(*MemoryAccount)\n\tif !ok {\n\t\treturn errors.New(\"user account is not valid\")\n\t}\n\n\tvar newCtx context.Context\n\tvar newCancel context.CancelFunc\n\tif session.TimeoutOnlyFromContext(ctx) {\n\t\tnewCtx, newCancel = context.WithCancel(context.Background())\n\t}\n\n\tsessionPolicy := c.policyManager.ForLevel(user.Level)\n\tctx, cancel := context.WithCancel(ctx)\n\ttimer := signal.CancelAfterInactivity(ctx, func() {\n\t\tcancel()\n\t\tif newCancel != nil {\n\t\t\tnewCancel()\n\t\t}\n\t}, sessionPolicy.Timeouts.ConnectionIdle)\n\n\tpostRequest := func() error {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/trojan/client.go#L63-L99","documentation":"Thrown by the trojan client when the configured server user's Account is not a *MemoryAccount (the trojan protocol's internal account type holding the key). This is a programming/registration error: the user object attached to the server spec was built with a different account type than trojan's protocol.RegisterAccount produces.","triggerScenarios":"server.User.Account type-asserts to *MemoryAccount and fails — e.g. a custom builder inserted a *protocol.AccountUser or a nil/default account, or a fork changed the account type without updating this client.","commonSituations":"Vendored fork of xray-core where account types were refactored; embedding code constructing ServerSpec users manually with the wrong account implementation; version skew between core and a custom trojan handler.","solutions":["Construct trojan users through the documented path so accounts are parsed via trojan's account registration (config user -> protocol.MemoryAccount with Key derived from password).","If maintaining a fork, keep the type-assert target in sync with the registered account type.","Regenerate the server spec from protobuf (NewServerSpecFromPB) instead of hand-building user objects."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isTrojanMemoryAccount(a interface{}) bool {\n\t_, ok := a.(*trojan.MemoryAccount)\n\treturn ok\n}","tryCatchPattern":null,"preventionTips":["Always build users via protocol registration paths, never by hand.","In forks, keep account type assertions next to their registration in one package.","Add a compile-time var _ = ... assertion tying the client to the account type."],"tags":["trojan","account","type-assertion","internal","embedding"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}