syncthing/syncthing · warning
UPnP Error: %s (%d)
Error message
UPnP Error: %s (%d)
What it means
The IGD gateway returned a SOAP fault for AddPortMapping that is not error 725 (which syncthing auto-repairs by retrying with a permanent lease). The gateway's own description and error code are embedded, e.g. 718 ConflictInMappingEntry, 727 ExternalPortOnlySupportsWildcard, 606 ActionNotAuthorized.
Source
Thrown at lib/upnp/igd_service.go:211
<NewEnabled>1</NewEnabled>
<NewPortMappingDescription>%s</NewPortMappingDescription>
<NewLeaseDuration>%d</NewLeaseDuration>
</u:AddPortMapping>`
body := fmt.Sprintf(template, s.URN, externalPort, protocol, internalPort, s.LocalIPv4, description, duration/time.Second)
response, err := soapRequestWithIP(ctx, s.URL, s.URN, "AddPortMapping", body, &net.TCPAddr{IP: s.LocalIPv4})
if err != nil && duration > 0 {
// Try to repair error code 725 - OnlyPermanentLeasesSupported
var envelope soapErrorResponse
if unmarshalErr := xml.Unmarshal(response, &envelope); unmarshalErr != nil {
return externalPort, unmarshalErr
}
if envelope.ErrorCode == 725 {
return s.AddPortMapping(ctx, protocol, internalPort, externalPort, description, 0)
}
err = fmt.Errorf("UPnP Error: %s (%d)", envelope.ErrorDescription, envelope.ErrorCode)
l.Debugf("Couldn't add port mapping for %s (external port %d -> internal port %d/%s): %s", s.LocalIPv4, externalPort, internalPort, protocol, err)
}
return externalPort, err
}
// DeletePortMapping deletes a port mapping from the specified IGD service.
func (s *IGDService) DeletePortMapping(ctx context.Context, protocol nat.Protocol, externalPort int) error {
const template = `<u:DeletePortMapping xmlns:u="%s">
<NewRemoteHost></NewRemoteHost>
<NewExternalPort>%d</NewExternalPort>
<NewProtocol>%s</NewProtocol>
</u:DeletePortMapping>`
body := fmt.Sprintf(template, s.URN, externalPort, protocol)
_, err := soapRequest(ctx, s.URL, s.URN, "DeletePortMapping", body)
return errView on GitHub (pinned to 058bcd7334)
Solutions
- Match the error code: 718 → change to a different external port; 606 → enable UPnP or authorize the client in the router; 728 → reboot router to clear the full mapping table
- Delete the conflicting static port-forward in the router admin UI, or pick a unique external port for this device
- Set 'externalPort' in syncthing's config for the device instead of automatic discovery
- Fall back to manual port forwarding and disable NAT discovery in syncthing if the gateway's UPnP is broken
Defensive patterns
Strategy: fallback
Try / catch
extPort, err := svc.AddPortMapping(ctx, proto, intPort, extPort, desc, lease)
if err != nil {
if strings.Contains(err.Error(), "718") { // ConflictInMappingEntry
// retry with a different external port
}
// else disable auto-mapping for this device and configure the forward manually
} Prevention
- Assign each syncthing device behind a shared router a unique external port
- Avoid mixing static router port-forwards with UPnP on the same port
- Test UPnP health after router firmware upgrades before relying on automatic mapping
When it happens
Trigger: IGDService.AddPortMapping with duration > 0 where the gateway rejects the mapping: another host already holds the external port (718), the router requires authorization (606), or the description/port parameters exceed what the device supports. Note the 725 path recursively retries with duration 0.
Common situations: Two devices behind the same router requesting the same external port; router UPnP table exhausted; ISP gateways with UPnP disabled/filtered (failure/606); conflicting static port-forward configured in the router admin UI.
Related errors
- UPnP error: %s (%d)
- connected to self
- get default port (GUI): %w
- get free port (GUI): %w
- get free port (BEP): %w
AI-assisted analysis of syncthing/syncthing@058bcd7334 (2026-08-15).
Data as JSON: /api/errors/d9a6f9c82d02a646.
Report an issue: GitHub.