@@ -308,6 +308,23 @@ func (s *Server) attachDuckLake(db *sql.DB) error {
308308 return nil // DuckLake not configured
309309 }
310310
311+ // Serialize DuckLake attachment to avoid race conditions
312+ // Multiple connections trying to attach simultaneously can cause
313+ // "database with name '__ducklake_metadata_ducklake' already exists" errors
314+ s .duckLakeMu .Lock ()
315+ defer s .duckLakeMu .Unlock ()
316+
317+ // Check if DuckLake catalog is already attached
318+ var count int
319+ err := db .QueryRow ("SELECT COUNT(*) FROM duckdb_databases() WHERE database_name = 'ducklake'" ).Scan (& count )
320+ if err == nil && count > 0 {
321+ // Already attached, just set as default
322+ if _ , err := db .Exec ("USE ducklake" ); err != nil {
323+ return fmt .Errorf ("failed to set DuckLake as default catalog: %w" , err )
324+ }
325+ return nil
326+ }
327+
311328 // Create S3 secret if using object store
312329 // - With explicit credentials (S3AccessKey set) or custom endpoint
313330 // - With credential_chain provider (for AWS S3)
@@ -359,13 +376,9 @@ func (s *Server) attachDuckLake(db *sql.DB) error {
359376// - "config": explicit credentials (for MinIO or when you have access keys)
360377// - "credential_chain": AWS SDK credential chain (env vars, config files, instance metadata, etc.)
361378//
379+ // Note: Caller must hold duckLakeMu to avoid race conditions.
362380// See: https://duckdb.org/docs/stable/core_extensions/httpfs/s3api
363381func (s * Server ) createS3Secret (db * sql.DB ) error {
364- // Serialize secret creation to avoid DuckDB write-write conflicts
365- // when multiple connections try to create the same secret simultaneously
366- s .duckLakeMu .Lock ()
367- defer s .duckLakeMu .Unlock ()
368-
369382 // Check if secret already exists to avoid unnecessary creation
370383 var count int
371384 err := db .QueryRow ("SELECT COUNT(*) FROM duckdb_secrets() WHERE name = 'ducklake_s3'" ).Scan (& count )
0 commit comments