googleapis/mcp-toolbox · error

unable to get logger from ctx: %s

Error message

unable to get logger from ctx: %s

What it means

initTrinoConnectionPool fetches the structured logger from the context via util.LoggerFromContext and wraps a non-nil error with this message. Unlike the other wraps it uses %s formatting, so the underlying cause is not chainable. It indicates the request context did not carry the logger the toolbox expects.

Source

Thrown at internal/sources/trino/trino.go:179

	}

	return out, nil
}

func initTrinoConnectionPool(ctx context.Context, tracer trace.Tracer, name, host, port, user, password, catalog, schema, queryTimeout, accessToken string, kerberosEnabled, sslEnabled bool, sslCertPath, sslCert string, disableSslVerification bool) (*sql.DB, error) {
	//nolint:all // Reassigned ctx
	ctx, span := sources.InitConnectionSpan(ctx, tracer, SourceType, name)
	defer span.End()

	// Build Trino DSN
	dsn, err := buildTrinoDSN(host, port, user, password, catalog, schema, queryTimeout, accessToken, kerberosEnabled, sslEnabled, sslCertPath, sslCert)
	if err != nil {
		return nil, fmt.Errorf("failed to build DSN: %w", err)
	}

	logger, err := util.LoggerFromContext(ctx)
	if err != nil {
		return nil, fmt.Errorf("unable to get logger from ctx: %s", err)
	}

	if disableSslVerification {
		logger.WarnContext(ctx, "SSL verification is disabled for trino source %s. This is an insecure setting and should not be used in production.\n", name)
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		}
		client := &http.Client{Transport: tr}
		clientName := fmt.Sprintf("insecure_trino_client_%s", name)
		if err := trinogo.RegisterCustomClient(clientName, client); err != nil {
			return nil, fmt.Errorf("failed to register custom client: %w", err)
		}
		dsn = fmt.Sprintf("%s&custom_client=%s", dsn, clientName)
	}

	db, err := sql.Open("trino", dsn)
	if err != nil {
		return nil, fmt.Errorf("failed to open connection: %w", err)

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Pass a context derived through the toolbox server/middleware pipeline that injects the logger
  2. In tests or custom code, add the logger to the context the same way the server does (util.NewContextWithLogger-style helper)
  3. Upgrade the toolbox version if logger injection behavior changed
  4. Note this fires before any DB call — fix the caller, not the Trino config

Example fix

// before
src, err := cfg.Initialize(context.Background(), tracer)
// after
ctx := util.NewContextWithLogger(context.Background(), logger)
src, err := cfg.Initialize(ctx, tracer)
Defensive patterns

Strategy: validation

Validate before calling

// ensure logger is present before calling Initialize
if logger := ctx.Value(loggerKey{}); logger == nil {
    ctx = util.NewContextWithLogger(ctx, slog.Default())
}
src, err := cfg.Initialize(ctx, tracer)

Type guard

func ctxHasLogger(ctx context.Context) bool {
    l, err := util.LoggerFromContext(ctx)
    return err == nil && l != nil
}

Try / catch

src, err := cfg.Initialize(ctx, tracer)
if err != nil && strings.Contains(err.Error(), "unable to get logger from ctx") {
    // inject logger and retry once
    ctx = util.NewContextWithLogger(ctx, slog.Default())
    src, err = cfg.Initialize(ctx, tracer)
}

Prevention

When it happens

Trigger: Initialize -> initTrinoConnectionPool where the passed ctx lacks the logger util.LoggerFromContext expects — i.e. Initialize invoked with a bare/foreign context rather than one prepared by the toolbox server pipeline.

Common situations: Custom integrations calling Config.Initialize directly with context.Background(); tests constructing sources outside the toolbox server lifecycle; middleware that stripped or replaced the context values.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/d3add9a526053610. Report an issue: GitHub.