{"record":{"id":"73680117f85ff3ee","repo":"Tencent/WeKnora","slug":"types-tenantidcontextkey-not-set-in-context","errorCode":null,"errorMessage":"types.TenantIDContextKey not set in context","messagePattern":"types\\.TenantIDContextKey not set in context","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/types/context_helpers.go","lineNumber":34,"sourceCode":"func DefaultLanguage() string {\n\tif lang := EnvLanguage(); lang != \"\" {\n\t\treturn lang\n\t}\n\treturn \"zh-CN\"\n}\n\n// TenantIDFromContext extracts the tenant ID from ctx.\n// Returns (0, false) when the key is absent or the value is not uint64.\nfunc TenantIDFromContext(ctx context.Context) (uint64, bool) {\n\tv, ok := ctx.Value(TenantIDContextKey).(uint64)\n\treturn v, ok\n}\n\n// MustTenantIDFromContext extracts the tenant ID from ctx, panicking if missing.\nfunc MustTenantIDFromContext(ctx context.Context) uint64 {\n\tv, ok := TenantIDFromContext(ctx)\n\tif !ok {\n\t\tpanic(\"types.TenantIDContextKey not set in context\")\n\t}\n\treturn v\n}\n\n// TenantInfoFromContext extracts the *Tenant from ctx.\nfunc TenantInfoFromContext(ctx context.Context) (*Tenant, bool) {\n\tv, ok := ctx.Value(TenantInfoContextKey).(*Tenant)\n\treturn v, ok && v != nil\n}\n\n// RequestIDFromContext extracts the request ID string from ctx.\nfunc RequestIDFromContext(ctx context.Context) (string, bool) {\n\tv, ok := ctx.Value(RequestIDContextKey).(string)\n\treturn v, ok && v != \"\"\n}\n\n// UserIDFromContext extracts the user ID string from ctx.\nfunc UserIDFromContext(ctx context.Context) (string, bool) {","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/types/context_helpers.go#L16-L52","documentation":"MustTenantIDFromContext is the non-optional variant of TenantIDFromContext: it panics when the TenantIDContextKey value is absent from the request context. Multi-tenant handlers call it to obtain the tenant ID, so a missing value means an upstream middleware failed to inject the tenant.","triggerScenarios":"Any handler path that calls MustTenantIDFromContext (OnEvent, GetChunkByID, ListChunksByKnowledgeID, ListPagedChunksByKnowledgeID, DeleteChunk, DeleteChunks) when the tenant-injection middleware did not run or did not set TenantIDContextKey — e.g. route registered without the middleware, middleware skipped on error, or a manually constructed context in tests.","commonSituations":"A new route added without the tenant middleware; background/async jobs carrying a bare context.Background(); websocket/event handlers (OnEvent) using a context that never passed through HTTP middleware; tests calling handlers directly with plain contexts.","solutions":["Ensure the tenant middleware runs before the handler and always sets TenantIDContextKey (fail the request in middleware when the tenant cannot be resolved)","Switch the handler to the safe TenantIDFromContext and return a 401/400 error instead of panicking","In tests/background jobs, build the context with the helper that sets the tenant ID (e.g. context.WithValue(ctx, TenantIDContextKey, id))","Add a startup check that asserts tenant middleware is attached to all tenant-scoped routes"],"exampleFix":"// before\ntenantID := types.MustTenantIDFromContext(c.Request.Context())\n// after\ntenantID, ok := types.TenantIDFromContext(c.Request.Context())\nif !ok {\n    c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{\"error\": \"missing tenant\"})\n    return\n}","handlingStrategy":"type-guard","validationCode":"tenantID, ok := types.TenantIDFromContext(ctx)\nif !ok {\n    // handle: 401 / reject request before calling the Must* helper\n}","typeGuard":"func hasTenantID(ctx context.Context) bool {\n    _, ok := types.TenantIDFromContext(ctx)\n    return ok\n}","tryCatchPattern":"func tenantIDOrErr(ctx context.Context) (id uint64, err error) {\n    defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"missing tenant: %v\", r) } }()\n    return types.MustTenantIDFromContext(ctx), nil\n}","preventionTips":["Attach the tenant middleware to every tenant-scoped route and verify in tests","Prefer the (value, ok) variant in handlers where a missing tenant is a client error","In background jobs/tests, always build contexts via the tenant-injecting helper"],"tags":["go","panic","context","multi-tenancy","middleware"],"backgroundTag":"missing-context-value","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}