{"record":{"id":"7d03b3ec45e3152f","repo":"netbirdio/netbird","slug":"converting-fd-to-file-failed","errorCode":null,"errorMessage":"converting fd to file failed","messagePattern":"converting fd to file failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/iface/wgproxy/rawsocket/rawsocket.go","lineNumber":78,"sourceCode":"\t\treturn nil, fmt.Errorf(\"binding to lo interface failed: %w\", err)\n\t}\n\n\t// Set the fwmark on the socket.\n\terr = nbnet.SetSocketOpt(fd)\n\tif err != nil {\n\t\tif closeErr := syscall.Close(fd); closeErr != nil {\n\t\t\tlog.Warnf(\"failed to close raw socket fd: %v\", closeErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"setting fwmark failed: %w\", err)\n\t}\n\n\t// Convert the file descriptor to a PacketConn.\n\tfile := os.NewFile(uintptr(fd), fmt.Sprintf(\"fd %d\", fd))\n\tif file == nil {\n\t\tif closeErr := syscall.Close(fd); closeErr != nil {\n\t\t\tlog.Warnf(\"failed to close raw socket fd: %v\", closeErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"converting fd to file failed\")\n\t}\n\tpacketConn, err := net.FilePacketConn(file)\n\tif err != nil {\n\t\tif closeErr := file.Close(); closeErr != nil {\n\t\t\tlog.Warnf(\"failed to close file: %v\", closeErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"converting file to packet conn failed: %w\", err)\n\t}\n\n\t// Close the original file to release the FD (net.FilePacketConn duplicates it)\n\tif closeErr := file.Close(); closeErr != nil {\n\t\tlog.Warnf(\"failed to close file after creating packet conn: %v\", closeErr)\n\t}\n\n\treturn packetConn, nil\n}\n","sourceCodeStart":60,"sourceCodeEnd":95,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/wgproxy/rawsocket/rawsocket.go#L60-L95","documentation":"Returned by rawsocket.prepareSenderRawSocket when os.NewFile(uintptr(fd), ...) returns nil. os.NewFile in modern Go never returns nil for a valid non-negative fd; it returns nil only if handed something like an invalid handle. Because fd comes straight from a successful syscall.Socket, this branch is a defensive invariant check that is effectively unreachable.","triggerScenarios":"Only reachable if syscall.Socket returned a nonsensical fd value (negative or otherwise invalid) without error, or Go runtime internals changed under the code. No realistic API call produces it.","commonSituations":"Practically never seen; if it ever fires, suspect memory corruption, an aggressively patched runtime, or a fork of the repo that changed the fd plumbing above this call.","solutions":["Treat as an internal invariant failure: report the fd value and Go version to NetBird","Audit any local fork for code that closes or reuses the fd between syscall.Socket and os.NewFile","No configuration change affects this path"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// treat as an invariant breach: nothing at call-site level can prevent it\nif _, err := rawsocket.PrepareSenderRawSocketIPv4(); err != nil && strings.Contains(err.Error(), \"converting fd to file\") {\n    panic(fmt.Sprintf(\"raw socket fd invariant broken: %v\", err)) // surfaces the bug instead of half-starting\n}","preventionTips":["Do not fork the fd handling between syscall.Socket and os.NewFile","Consider this branch dead code when triaging; spend effort on reachable errors first"],"tags":["go","netbird","raw-socket","unreachable-invariant","linux"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}