{"record":{"id":"83565edc175575ef","repo":"Tencent/WeKnora","slug":"failed-to-get-tenant-w","errorCode":null,"errorMessage":"failed to get tenant: %w","messagePattern":"failed to get tenant: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/message.go","lineNumber":449,"sourceCode":"\t\treturn\n\t}\n\n\tif len(knowledgeIDs) == 0 {\n\t\treturn\n\t}\n\n\tlogger.Infof(ctx, \"Deleting %d chat history knowledge entries for session %s\", len(knowledgeIDs), sessionID)\n\tif err := s.knowService.DeleteKnowledgeList(ctx, knowledgeIDs); err != nil {\n\t\tlogger.Warnf(ctx, \"Failed to batch delete chat history knowledge for session %s: %v\", sessionID, err)\n\t}\n}\n\n// GetChatHistoryKBStats returns statistics about the chat history knowledge base.\nfunc (s *messageService) GetChatHistoryKBStats(ctx context.Context) (*types.ChatHistoryKBStats, error) {\n\ttenantID := types.MustTenantIDFromContext(ctx)\n\ttenant, err := s.tenantService.GetTenantByID(ctx, tenantID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get tenant: %w\", err)\n\t}\n\n\tstats := &types.ChatHistoryKBStats{}\n\tcfg := tenant.ChatHistoryConfig\n\tif cfg == nil || !cfg.Enabled {\n\t\treturn stats, nil\n\t}\n\n\tstats.Enabled = true\n\tstats.EmbeddingModelID = cfg.EmbeddingModelID\n\tstats.KnowledgeBaseID = cfg.KnowledgeBaseID\n\n\tif cfg.KnowledgeBaseID == \"\" {\n\t\treturn stats, nil\n\t}\n\n\t// Fetch KB info and fill counts (KnowledgeCount is gorm:\"-\", needs FillKnowledgeBaseCounts)\n\tkb, err := s.kbService.GetKnowledgeBaseByID(ctx, cfg.KnowledgeBaseID)","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/message.go#L431-L467","documentation":"GetChatHistoryKBStats needs the tenant record to read its ChatHistoryConfig. It calls tenantService.GetTenantByID with the tenant ID from context; any failure fetching the tenant is wrapped here, so stats cannot be computed.","triggerScenarios":"Calling GetChatHistoryKBStats with a context whose tenant ID does not exist, has been deleted, or when the tenant service/repository errors (DB down, timeout, permission issue).","commonSituations":"Stale tenant ID in auth context after tenant deletion; cross-tenant request where the tenant row was never created; tenant service DB outage.","solutions":["Check the wrapped error from GetTenantByID for the root cause (not found vs connection failure).","Verify types.MustTenantIDFromContext(ctx) yields a valid, existing tenant ID.","Confirm the tenant exists in the database and was not soft-deleted.","If not-found, re-authenticate so the context carries a current tenant ID."],"exampleFix":"// before\ntenantID := types.MustTenantIDFromContext(ctx)\ntenant, err := s.tenantService.GetTenantByID(ctx, tenantID)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to get tenant: %w\", err)\n}\n// after\ntenantID, err := types.TenantIDFromContext(ctx)\nif err != nil {\n    return nil, fmt.Errorf(\"missing tenant in context: %w\", err)\n}\ntenant, err := s.tenantService.GetTenantByID(ctx, tenantID)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to get tenant: %w\", err)\n}","handlingStrategy":"type-guard","validationCode":"tenantID, ok := types.TenantIDFromContext(ctx)\nif !ok || tenantID == 0 { return fmt.Errorf(\"no tenant in context\") }","typeGuard":"func hasTenant(ctx context.Context) bool {\n    id, err := types.TenantIDFromContext(ctx)\n    return err == nil && id != 0\n}","tryCatchPattern":"stats, err := svc.GetChatHistoryKBStats(ctx)\nif err != nil && strings.Contains(err.Error(), \"failed to get tenant\") {\n    // tenant missing/deleted: force re-auth or return 404 to client\n}","preventionTips":["Always set the tenant ID in middleware before service calls","Soft-delete checks: verify tenant exists before issuing tokens carrying its ID","Cache tenant lookups to reduce dependence on tenant DB availability"],"tags":["tenant","database","context"],"backgroundTag":"tenant-lookup-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}