@@ -375,6 +375,13 @@ internal final class EtcdHttpClient: @unchecked Sendable {
375375
376376 do {
377377 try await detectApiPrefix ( )
378+ } catch let etcdError as EtcdError {
379+ lock. lock ( )
380+ session? . invalidateAndCancel ( )
381+ session = nil
382+ lock. unlock ( )
383+ Self . logger. error ( " Connection test failed: \( etcdError. localizedDescription) " )
384+ throw etcdError
378385 } catch {
379386 lock. lock ( )
380387 session? . invalidateAndCancel ( )
@@ -453,19 +460,32 @@ internal final class EtcdHttpClient: @unchecked Sendable {
453460 throw EtcdError . serverError ( " Invalid response type " )
454461 }
455462
456- if httpResponse. statusCode == 404 {
463+ switch httpResponse. statusCode {
464+ case 404 :
457465 continue
466+ case 200 :
467+ lock. lock ( )
468+ apiPrefix = candidate
469+ lock. unlock ( )
470+ Self . logger. debug ( " Detected etcd API prefix: \( candidate) " )
471+ return
472+ case 401 where !config. username. isEmpty:
473+ // Auth required but credentials are configured — prefix is valid,
474+ // authenticate() will run after detection
475+ lock. lock ( )
476+ apiPrefix = candidate
477+ lock. unlock ( )
478+ Self . logger. debug ( " Detected etcd API prefix: \( candidate) (auth required) " )
479+ return
480+ case 401 :
481+ throw EtcdError . authFailed ( " Authentication required " )
482+ default :
483+ Self . logger. warning ( " Prefix probe \( candidate) returned HTTP \( httpResponse. statusCode) " )
484+ throw EtcdError . serverError ( " Unexpected HTTP \( httpResponse. statusCode) from \( candidate) /maintenance/status " )
458485 }
459-
460- // Any non-404 (200, 401, etc.) means this prefix exists on the server
461- lock. lock ( )
462- apiPrefix = candidate
463- lock. unlock ( )
464- Self . logger. debug ( " Detected etcd API prefix: \( candidate) " )
465- return
466486 }
467487
468- throw EtcdError . connectionFailed (
488+ throw EtcdError . serverError (
469489 " No supported etcd API found (tried: \( candidates. joined ( separator: " , " ) ) ) "
470490 )
471491 }
0 commit comments