{"record":{"id":"121bd829c7f7c476","repo":"Billionmail/BillionMail","slug":"account-id-not-found-in-context","errorCode":null,"errorMessage":"account ID not found in context","messagePattern":"account ID not found in context","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/rbac/account.go","lineNumber":322,"sourceCode":"\tvalue := ctx.Value(\"roles\")\n\tif value == nil {\n\t\treturn []string{}\n\t}\n\n\troles, ok := value.([]string)\n\tif !ok {\n\t\treturn []string{}\n\t}\n\n\treturn roles\n}\n\n// GetCurrentAccount gets the current user account from context\nfunc GetCurrentAccount(ctx context.Context) (acc *model.Account, err error) {\n\taccountId := GetCurrentAccountId(ctx)\n\n\tif accountId == 0 {\n\t\treturn nil, fmt.Errorf(\"account ID not found in context\")\n\t}\n\n\tif err = g.DB().Model(\"account\").Where(\"account_id = ?\", accountId).Scan(&acc); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get account: %w\", err)\n\t}\n\n\treturn\n}\n","sourceCodeStart":304,"sourceCodeEnd":331,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/rbac/account.go#L304-L331","documentation":"GetCurrentAccount reads the authenticated account ID from the request context (set by auth middleware) and loads the account row. If the ID is missing/zero, it means the caller ran without authentication context — the middleware didn't run or the claim wasn't stored. The library refuses to guess the identity.","triggerScenarios":"Calling GetCurrentAccount(ctx) in a route not wrapped by JWT auth middleware, in background jobs/goroutines using context.Background(), or after auth middleware failed to inject the account ID.","commonSituations":"New endpoint added without the auth middleware group; cron/scheduled tasks calling user-scoped helpers; WebSocket or callback handlers that skip the standard middleware chain.","solutions":["Ensure the route is registered inside the authenticated middleware group so account ID is injected into context.","In non-HTTP contexts, pass the account ID explicitly instead of relying on context.","Check the auth middleware actually ran (order of middleware registration) and stored the account ID key this function reads.","Debug the token: expired/invalid tokens may short-circuit middleware before the ID is set."],"exampleFix":"// before (unauthenticated route)\nrouter.Bind(controller.Profile)\n// after\nrouter.Group(\"/api\", func(group *ghttp.RouterGroup) {\n    group.Middleware(service.AuthMiddleware)\n    group.Bind(controller.Profile)\n})","handlingStrategy":"type-guard","validationCode":"if service.GetCurrentAccountId(ctx) == 0 {\n    return gerror.NewCode(gcode.CodeNotAuthorized, \"login required\")\n}\nacc, err := service.GetCurrentAccount(ctx)","typeGuard":"func hasAuthContext(ctx context.Context) bool {\n    return service.GetCurrentAccountId(ctx) != 0\n}","tryCatchPattern":"acc, err := service.GetCurrentAccount(ctx)\nif err != nil {\n    if strings.Contains(err.Error(), \"account ID not found in context\") {\n        return gerror.NewCode(gcode.CodeNotAuthorized)\n    }\n    return err\n}","preventionTips":["Register user-scoped routes only inside the authenticated middleware group.","Never call GetCurrentAccount from background jobs with context.Background().","Add an integration test asserting unauthenticated requests get 401, not this error.","Keep middleware key names in sync with the reader function."],"tags":["auth","context","rbac"],"backgroundTag":"missing-auth-context","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}