{"record":{"id":"643e2ba01663c58e","repo":"syncthing/syncthing","slug":"already-connected-to-this-device","errorCode":null,"errorMessage":"already connected to this device","messagePattern":"already connected to this device","errorType":"exception","errorClass":"errDeviceAlreadyConnected","httpStatus":null,"severity":"info","filePath":"lib/connections/service.go","lineNumber":69,"sourceCode":"\nvar (\n\tdialers   = make(map[string]dialerFactory)\n\tlisteners = make(map[string]listenerFactory)\n)\n\nvar (\n\t// Dialers and listeners return errUnsupported (or a wrapped variant)\n\t// when they are intentionally out of service due to configuration,\n\t// build, etc. This is not logged loudly.\n\terrUnsupported = errors.New(\"unsupported protocol\")\n\n\t// These are specific explanations for errUnsupported.\n\terrDisabled   = fmt.Errorf(\"%w: disabled by configuration\", errUnsupported)\n\terrDeprecated = fmt.Errorf(\"%w: deprecated\", errUnsupported)\n\n\t// Various reasons to reject a connection\n\terrNetworkNotAllowed      = errors.New(\"network not allowed\")\n\terrDeviceAlreadyConnected = errors.New(\"already connected to this device\")\n\terrDeviceIgnored          = errors.New(\"device is ignored\")\n\terrConnLimitReached       = errors.New(\"connection limit reached\")\n\terrDevicePaused           = errors.New(\"device is paused\")\n\n\t// A connection is being closed to make space for better ones\n\terrReplacingConnection = errors.New(\"replacing connection\")\n)\n\nconst (\n\tperDeviceWarningIntv          = 15 * time.Minute\n\ttlsHandshakeTimeout           = 10 * time.Second\n\tminConnectionLoopSleep        = 5 * time.Second\n\tstdConnectionLoopSleep        = time.Minute\n\tworstDialerPriority           = math.MaxInt32\n\trecentlySeenCutoff            = 7 * 24 * time.Hour\n\tshortLivedConnectionThreshold = 5 * time.Second\n\tdialMaxParallel               = 64\n\tdialMaxParallelPerDevice      = 8","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/syncthing/syncthing/blob/058bcd7334839663cf569501d3ac539034d45cb5/lib/connections/service.go#L51-L87","documentation":"errDeviceAlreadyConnected is a connection-rejection sentinel meaning the service already has a connection to that device ID, so the new candidate connection is refused instead of duplicating it. Syncthing keeps (at most) one preferred connection per device; when several candidates arrive (both sides dialing, multiple addresses), losers are rejected with this error and the dial loop treats it as success-equivalent, not a failure.","triggerScenarios":"Two devices dial each other simultaneously, or a device answers while an outbound dial to it is in flight; the second candidate hits the already-connected check in the connection service and is rejected with errDeviceAlreadyConnected.","commonSituations":"Symmetric setups where both configs list each other (the normal case) causing connection races; log noise showing the error even though connectivity is fine.","solutions":["No action needed if syncing works: this is normal connection de-duplication, treat it as informational.","If connections flap, check NAT/relay churn that causes constant re-dialing rather than this error itself.","When writing tooling around the connection service, handle this sentinel explicitly so it is not reported as a failure."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := dialDevice(id); err != nil {\n    if errors.Is(err, errDeviceAlreadyConnected) {\n        // success-equivalent: a connection already exists; reuse it\n        return existingConn(id)\n    }\n}","preventionTips":["Check for an existing connection before initiating a new one when embedding Syncthing.","Treat this sentinel as benign in monitoring and dashboards.","Do not configure alerting on it; alert on zero-connections instead."],"tags":["network","connections","deduplication","syncthing"],"backgroundTag":null,"analyzedSha":"058bcd7334839663cf569501d3ac539034d45cb5","analyzedAt":"2026-08-15T07:53:43.174Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}