{"record":{"id":"9edfef5152ea19f4","repo":"netbirdio/netbird","slug":"expected-ipv6-address-got-s","errorCode":null,"errorMessage":"expected IPv6 address, got %s","messagePattern":"expected IPv6 address, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/wgaddr/address.go","lineNumber":75,"sourceCode":"\t\treturn netip.Prefix{}\n\t}\n\treturn netip.PrefixFrom(addr.IPv6, addr.IPv6Net.Bits())\n}\n\n// SetIPv6FromCompact decodes a compact prefix (5 or 17 bytes) and sets the IPv6 fields.\n// Returns an error if the bytes are invalid. A nil or empty input is a no-op.\n//\n//nolint:recvcheck\nfunc (addr *Address) SetIPv6FromCompact(raw []byte) error {\n\tif len(raw) == 0 {\n\t\treturn nil\n\t}\n\tprefix, err := netiputil.DecodePrefix(raw)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"decode v6 overlay address: %w\", err)\n\t}\n\tif !prefix.Addr().Is6() {\n\t\treturn fmt.Errorf(\"expected IPv6 address, got %s\", prefix.Addr())\n\t}\n\taddr.IPv6 = prefix.Addr()\n\taddr.IPv6Net = prefix.Masked()\n\treturn nil\n}\n\n// ClearIPv6 removes the IPv6 overlay address, leaving only v4.\n//\n//nolint:recvcheck\nfunc (addr *Address) ClearIPv6() {\n\taddr.IPv6 = netip.Addr{}\n\taddr.IPv6Net = netip.Prefix{}\n}\n","sourceCodeStart":57,"sourceCodeEnd":89,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/wgaddr/address.go#L57-L89","documentation":"Thrown by wgaddr.Address.SetIPv6FromCompact when the compact byte blob decoded with netiputil.DecodePrefix yields a non-IPv6 address (prefix.Addr().Is6() is false, i.e. a plain v4 address). The method is the single entry point that fills the IPv6/IPv6Net overlay fields from serialized data (config file or network map from management), so the error means the sender put v4 data into the v6 slot. Note that Is6() accepts v4-mapped addresses like ::ffff:10.0.0.1, so this only fires for genuinely 4-byte/v4-encoded values.","triggerScenarios":"Management (or a hand-edited serialized state/config) writes an IPv4 prefix into the IPv6 field of the compact network map or config that SetIPv6FromCompact decodes. Concretely: agent upgrade/downgrade across versions that changed the compact encoding, a management bug, or test harnesses crafting the raw []byte with the wrong family.","commonSituations":"Version skew between agent and management after a partial upgrade; restoring a state file produced by a different agent build; self-hosted management patched to send v4 in the v6 slot. Per the repo's 'IPv6 is a soft feature' rule, a bad v6 payload should degrade to v4-only, not fail startup.","solutions":["Check agent and management versions match; the compact prefix encoding (5 vs 17 bytes) changed across releases, so resync by re-registering or updating the peer","Log the offending peer/account and skip the v6 assignment (ClearIPv6) instead of propagating the error, keeping the v4 overlay working","If you control the producer, fix it to only call the v4 compact encoding for the v4 field and the 17-byte v6 encoding for the v6 field","Reproduce by decoding the raw bytes with netiputil.DecodePrefix and printing prefix.Addr() to confirm which field is malformed"],"exampleFix":"// before\nif err := addr.SetIPv6FromCompact(raw); err != nil {\n    return fmt.Errorf(\"set v6 overlay address: %w\", err)\n}\n\n// after - v6 is soft, never break v4 for it\nif err := addr.SetIPv6FromCompact(raw); err != nil {\n    log.Warnf(\"ignoring invalid v6 overlay payload, continuing v4-only: %v\", err)\n    addr.ClearIPv6()\n}","handlingStrategy":"validation","validationCode":"// before assigning, confirm the compact blob really carries a v6 prefix\nfunc hasIPv6CompactPayload(raw []byte) bool {\n    if len(raw) == 0 {\n        return false\n    }\n    p, err := netiputil.DecodePrefix(raw)\n    return err == nil && p.Addr().Is6()\n}","typeGuard":"func isV6Prefix(p netip.Prefix) bool {\n    return p.IsValid() && p.Addr().Is6()\n}","tryCatchPattern":"err := addr.SetIPv6FromCompact(raw)\nif err != nil {\n    if strings.Contains(err.Error(), \"expected IPv6 address\") {\n        log.Warnf(\"peer sent v4 in v6 slot, continuing v4-only: %v\", err)\n        addr.ClearIPv6()\n    } else {\n        return err // decode failure is a different problem\n    }\n}","preventionTips":["Keep agent and management versions aligned; the compact prefix wire format has changed across releases","Never serialize a v4 compact prefix into the IPv6 field of the network map or state file","Treat v6 as soft per NetBird convention: log and skip, never fail the v4 overlay because of v6 data"],"tags":["go","netbird","ipv6","address-parsing","version-mismatch"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}