{"record":{"id":"6e83914d218ae7c0","repo":"apache/seatunnel","slug":"failed-to-close-old-metadataprovider-of-kind","errorCode":null,"errorMessage":"Failed to close old MetadataProvider of kind: {}","messagePattern":"Failed to close old MetadataProvider of kind: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"seatunnel-api/src/main/java/org/apache/seatunnel/api/metadata/MetadataProviderManager.java","lineNumber":146,"sourceCode":"     * @param config the configuration for the provider\n     * @return initialized MetadataProvider instance\n     */\n    private static MetadataProvider getOrCreateProvider(String kind, Config config) {\n        // First check: fast path - return if cached provider matches requested kind\n        MetadataProvider provider = cachedProvider;\n        if (provider != null && provider.kind().equalsIgnoreCase(kind)) {\n            return provider;\n        }\n        synchronized (MetadataProviderManager.class) {\n            // Re-read volatile variable to see other threads' updates\n            provider = cachedProvider;\n            // Handle kind mismatch: close old provider before creating new one\n            if (provider != null && !provider.kind().equalsIgnoreCase(kind)) {\n                log.info(\"Provider kind changed from {} to {}\", provider.kind(), kind);\n                try {\n                    provider.close();\n                } catch (Exception e) {\n                    log.warn(\n                            \"Failed to close old MetadataProvider of kind: {}\", provider.kind(), e);\n                }\n                cachedProvider = null;\n                provider = null;\n            }\n            // Create new provider if needed (null or just closed due to kind mismatch)\n            if (provider == null) {\n                provider = MetadataProviderFactory.getProvider(kind);\n                provider.init(config);\n                cachedProvider = provider;\n                log.info(\"Created and cached new MetadataProvider: {}\", kind);\n            }\n        }\n        return provider;\n    }\n\n    /**\n     * Resolves and merges data source configuration for a single connector config.","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-api/src/main/java/org/apache/seatunnel/api/metadata/MetadataProviderManager.java#L128-L164","documentation":"MetadataProviderManager.getOrCreateProvider caches a singleton MetadataProvider; when a request asks for a provider of a different kind than the cached one, it closes the old provider before creating the new one. If the old provider's close() throws, the warning 'Failed to close old MetadataProvider of kind: {}' is logged and cleanup continues (cachedProvider reset to null anyway).","triggerScenarios":"Calling provider(kind) with a different kind than the currently cached provider while the old provider's close() throws (e.g. an unclosed JDBC/catalog connection, network timeout during shutdown).","commonSituations":"Switching metadata provider kinds (e.g. from JDBC to a REST metadata service) within one JVM; a metadata datasource became unreachable so close() hangs/fails; provider implementations with buggy close() methods.","solutions":["Inspect the attached exception to see why close() failed (usually a leaked connection or unreachable metadata service).","Ensure the underlying metadata datasource is reachable so close() can release resources cleanly.","Fix/close the underlying resources (connections, clients) in the provider implementation's close().","The manager proceeds to create the new provider, so this warning is usually safe to tolerate once, but resource leaks should be fixed."],"exampleFix":"// before (provider impl)\n@Override\npublic void close() {\n    connection.close(); // throws if already dead\n}\n// after\n@Override\npublic void close() {\n    try {\n        if (connection != null) connection.close();\n    } catch (Exception e) {\n        LOG.warn(\"error closing metadata connection\", e);\n    }\n}","handlingStrategy":"try-catch","validationCode":"// verify metadata datasource reachability before switching kinds\nif (!metadataService.ping()) throw new IllegalStateException(\"metadata service unreachable\");","typeGuard":"if (provider != null && !provider.kind().equalsIgnoreCase(kind)) { LOG.warn(\"kind switch {} -> {}\", provider.kind(), kind); }","tryCatchPattern":"try { manager.provider(newKind); } catch (Exception e) { LOG.warn(\"provider switch issue; old provider may have leaked resources\", e); }","preventionTips":["Stick to one provider kind per application where possible","Implement provider.close() defensively (never throw)","Release provider-held connections explicitly before switching kinds","Monitor for repeated warnings indicating resource leaks"],"tags":["metadata-provider","resource-cleanup","close-failure"],"backgroundTag":"file-write-failed","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}