Yeah, I've seen this one plenty of times. You fire up a Windows app that does any kind of network stuff, and boom: WSANOTINITIALISED. The error message is actually pretty honest—it's telling you that you never called WSAStartup, or that call failed. Let's fix it.
The Fix: Call WSAStartup Before Anything Else
If you're writing C or C++ on Windows with Winsock, the very first thing your program must do is initialize the socket library. That's what WSAStartup does. Missing it means every socket call returns this error, usually with error code 10093 (which is the decimal version of 0X0000276D).
Here's the correct pattern. This goes at the start of your program, before you call socket(), connect(), send(), or anything else:
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
int main() {
WSADATA wsaData;
int result = WSAStartup(MAKEWORD(2,2), &wsaData);
if (result != 0) {
printf("WSAStartup failed: %d\n", result);
return 1;
}
// ... your socket code here ...
WSACleanup(); // call this when done
return 0;
}
The MAKEWORD(2,2) asks for Winsock 2.2, which has been standard since Windows 2000. If you're on anything modern—Windows 10, 11, Server 2019+—that's what you want.
But here's the trap I see all the time: people call WSAStartup in one function, then try to use sockets in another function that runs later. Or they call it inside a conditional block that never executes. Or, worst of all, they call it after they've already tried to create a socket. The error appears the moment WinSock functions run without initialization.
Why This Works
Winsock isn't just a set of functions; it's a system service. WSAStartup tells Windows to load the Winsock DLL and negotiate the version you want. Until that happens, the socket functions have no backend. Think of it like plugging in a tool before using it—no power, no action.
When you call WSAStartup, it returns 0 if it works. If it doesn't, it gives you an error code that tells you why. Most common failures:
- WSAStartup itself returns SOCKET_ERROR (which is -1), and WSAGetLastError() gives you something like WSAVERNOTSUPPORTED (10092) if the version isn't available—rare on modern systems.
- Or the call fails if you're using an old build that links to wsock32.lib instead of ws2_32.lib. That mismatch can cause weird behavior.
Also, make sure you call WSACleanup when you're done. It's not strictly required because Windows cleans up on process exit, but it's good practice. I had a client whose app leaked handles because they never cleaned up, and eventually it froze. Not the same error, but it's the same carelessness.
Less Common Variations
Sometimes the fix isn't in your code at all. Here are a few real-world scenarios where this error shows up without you obviously missing WSAStartup:
1. DLL or Service Context
If your code runs inside a DLL that's loaded into a process, or as part of a Windows service, you need to call WSAStartup in the thread that actually uses sockets. Each thread that calls socket functions must have its own initialization if you're using Windows Sockets 1.1. But with Winsock 2.2, it's per-process, so that's less likely—but still, if you have multiple threads and only one calls WSAStartup, that's fine. The real gotcha is calling it from a DLL's DllMain—that's a no-go because WSAStartup can block.
2. C++ Static Initialization Order
I once debugged a C++ app where a global object's constructor opened a socket. The constructor ran before main(), so WSAStartup hadn't been called yet. Classic. The fix: move socket initialization to an explicit init function, or call WSAStartup at the top of main before anything else.
3. Python or Other Languages Wrapping Winsock
If you're using a Python library that wraps Winsock directly—like pywinsock—you might hit this if the library doesn't auto-init. Usually they do, but I've seen custom ctypes calls that forget. If you use ctypes to call socket functions, you must call WSAStartup yourself:
import ctypes
winsock = ctypes.windll.ws2_32
wsa = winsock.WSAStartup(0x0202, ctypes.byref(ctypes.c_ubyte(0)))
if wsa != 0:
raise RuntimeError(f"WSAStartup failed: {wsa}")
4. Static Linking vs Dynamic Linking
If you're linking statically with ws2_32.lib, you still need to call WSAStartup. The linker doesn't do it for you. I've had junior devs swear they linked it correctly but still got this error because they never called the init function.
Prevention
Stop this from happening again with a couple of habits:
- Always call WSAStartup at the very start of your program, before any network objects are created.
- Check the return value. Don't ignore it. If it fails, log the error code—that'll save you time later.
- Use a RAII wrapper in C++ that calls WSAStartup in its constructor and WSACleanup in its destructor. That way you can't forget.
And if you're inheriting code that's throwing this error, search for socket() calls before any WSAStartup. A quick grep will spot it. I did that for a client last week—their code had a global socket object created before main. Moved the WSAStartup call, and the error vanished.
Bottom line: this error is almost always a missing initialization call. Add WSAStartup, check its return, and you're good. If you're still stuck, check if you're calling socket functions from a thread that didn't init, or from a static initializer. That covers 99% of cases.