{"record":{"id":"c4175188e28da335","repo":"googleapis/mcp-toolbox","slug":"unable-to-get-logger-from-ctx-s-c41751","errorCode":null,"errorMessage":"unable to get logger from ctx: %s","messagePattern":"unable to get logger from ctx: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/looker/lookerhealthvacuum/lookerhealthvacuum.go","lineNumber":207,"sourceCode":"}\n\n// =================================================================================================================\n// END MCP SERVER CORE LOGIC\n// =================================================================================================================\n\n// =================================================================================================================\n// START LOOKER HEALTH VACUUM CORE LOGIC\n// =================================================================================================================\ntype vacuumTool struct {\n\tSdkClient  *v4.LookerSDK\n\ttimeframe  int\n\tminQueries int\n}\n\nfunc (t *vacuumTool) models(ctx context.Context, project, model string) ([]map[string]interface{}, error) {\n\tlogger, err := util.LoggerFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to get logger from ctx: %s\", err)\n\t}\n\tlogger.InfoContext(ctx, \"Vacuuming models...\")\n\n\tusedModels, err := t.getUsedModels(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlookmlModels, err := t.SdkClient.AllLookmlModels(v4.RequestAllLookmlModels{}, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error fetching LookML models: %w\", err)\n\t}\n\n\tvar results []map[string]interface{}\n\tfor _, m := range lookmlModels {\n\t\tif (project == \"\" || (m.ProjectName != nil && *m.ProjectName == project)) &&\n\t\t\t(model == \"\" || (m.Name != nil && *m.Name == model)) {\n","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/looker/lookerhealthvacuum/lookerhealthvacuum.go#L189-L225","documentation":"vacuumTool.models retrieves the structured logger from the request context via util.LoggerFromContext(ctx). The MCP server normally injects a logger into the context before invoking a tool; if it is absent (or the stored value fails the type assertion to the expected logger type), the tool aborts the models vacuum step and returns this wrapped error. Without the logger the tool cannot emit progress events during vacuuming.","triggerScenarios":"Calling vacuumTool.models (directly in tests, or via Invoke) with a bare context.Context that never had a logger attached — e.g. context.Background() in unit tests, or a code path that strips context values before calling the tool.","commonSituations":"Unit/integration tests constructing the tool and calling Invoke with ctx := context.Background(); custom harnesses that rebuild the request context and drop the server-injected logger; middleware that replaces the context instead of adding to it.","solutions":["Call the tool through the normal MCP server Invoke path, which attaches the logger to the context.","In tests, attach a logger first, e.g. ctx = util.WithLogger(ctx, logger) (or the project's helper) before invoking.","If using custom middleware, ensure it derives from the incoming ctx rather than replacing it with context.Background()."],"exampleFix":"// before\nerr := tool.Invoke(context.Background(), src, params, token)\n\n// after\nctx := util.WithLogger(context.Background(), slog.Default())\nerr := tool.Invoke(ctx, src, params, token)","handlingStrategy":"validation","validationCode":"if _, err := util.LoggerFromContext(ctx); err != nil {\n    ctx = util.WithLogger(ctx, slog.Default())\n}","typeGuard":"func ensureLogger(ctx context.Context) context.Context {\n    if _, err := util.LoggerFromContext(ctx); err != nil {\n        return util.WithLogger(ctx, slog.Default())\n    }\n    return ctx\n}","tryCatchPattern":"models, err := vt.models(ctx, project, model)\nif err != nil {\n    if strings.Contains(err.Error(), \"unable to get logger from ctx\") {\n        ctx = util.WithLogger(ctx, slog.Default())\n        models, err = vt.models(ctx, project, model)\n    }\n    return err\n}","preventionTips":["Never invoke tools with a bare context.Background(); always derive from the request context.","In tests, use a helper that injects a logger into the context before every tool call.","Avoid middleware that replaces the context wholesale; derive new contexts from the incoming one.","Wrap tool invocation in a helper that guarantees logger injection."],"tags":["looker","logging","context"],"backgroundTag":"missing-logger-in-context","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}