{"record":{"id":"a81a4f4daf4bceb9","repo":"googleapis/mcp-toolbox","slug":"unable-to-close-source-q-w","errorCode":null,"errorMessage":"unable to close source %q: %w","messagePattern":"unable to close source %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/sources/connect.go","lineNumber":148,"sourceCode":"// Close does not wait for an attempt that is already in flight. That attempt\n// releases its own result rather than caching it into a closed holder, so\n// shutdown never blocks on a connect that may be hung for the full timeout.\nfunc (c *ConnectOnce[T]) Close(ctx context.Context) error {\n\tc.mu.Lock()\n\tif c.closed {\n\t\tc.mu.Unlock()\n\t\treturn nil\n\t}\n\tvar zero T\n\tvalue, ready := c.value, c.ready\n\tc.value, c.ready, c.closed = zero, false, true\n\tc.mu.Unlock()\n\n\tif !ready {\n\t\treturn nil\n\t}\n\tif err := c.release(ctx, value); err != nil {\n\t\treturn fmt.Errorf(\"unable to close source %q: %w\", c.name, err)\n\t}\n\treturn nil\n}\n\n// Do returns the connection, making it on the first call. Concurrent callers\n// share one attempt, and a failed attempt is not remembered.\n//\n// Because a failure is retried by the next caller rather than cached, connect\n// must release whatever it had already built before it returns an error. A\n// pool that fails its ping and is returned unclosed leaks once per tool call,\n// not once per process.\nfunc (c *ConnectOnce[T]) Do(ctx context.Context, connect func(context.Context) (T, error)) (T, error) {\n\tvar zero T\n\tif value, ok := c.Get(); ok {\n\t\treturn value, nil\n\t}\n\tif c.isClosed() {\n\t\treturn zero, fmt.Errorf(\"unable to initialize source %q: source is closed\", c.name)","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/connect.go#L130-L166","documentation":"Returned by ConnectOnce.Close when releasing an already-initialized source connection fails. Close only attempts release if a connection is ready; if c.release(ctx, value) errors, the source's name and the underlying teardown error are wrapped. This indicates the resource cleanup (e.g., closing a DB pool) itself failed, not the shutdown flow.","triggerScenarios":"Server shutdown calls Close on a source whose connection was successfully created, but c.release returns an error while closing the underlying resource (e.g., pool.Close() or driver Close failing, or the release function's context being cancelled/expired).","commonSituations":"Database already severed mid-shutdown so pool close hangs or errors, driver-level failures during teardown, or a context deadline exceeded while draining connections at process exit.","solutions":["Inspect the wrapped cause (%w) to identify which underlying close operation failed","Check network connectivity to the database if release involves waiting for connections to drain","If this appears only at shutdown, it is usually benign — the process is exiting anyway; log and continue","Update drivers/SDK versions if the wrapped error points at a known driver teardown bug"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Wrap source Close and log rather than crash at shutdown\nif err := source.Close(ctx); err != nil {\n\tvar closedErr *fmt.wrapError // inspect wrapped cause\n\tlog.Printf(\"warning: source cleanup failed during shutdown: %v\", err)\n\t// non-fatal at shutdown unless cleanup is contractually required\n}","preventionTips":["Treat close-time errors as warnings during process exit","Ensure the database is reachable during drain if release needs cooperation","Check wrapped error text to distinguish driver teardown bugs from network loss","Keep driver/SDK versions current"],"tags":["shutdown","lifecycle","resource-cleanup","go"],"backgroundTag":"resource-close-failed","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"}