Quick answer: Check three things: STB_IMAGE_IMPLEMENTATION is defined in exactly one .cpp, the size you pass is the byte length (not sizeof on a pointer), and call stbi_failure_reason() to see why it failed.
Loading a PNG bundled into your asset archive via stb_image returns null. The image is valid — the call is wrong somewhere.
Define the Implementation Once
// in ONE .cpp file:
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
Other files just #include "stb_image.h" without the define. Forget the define entirely and the linker can’t find the load symbols.
Pass the Right Size
// WRONG: sizeof(buffer) on a pointer = sizeof(void*) = 8
stbi_load_from_memory(buffer, sizeof(buffer), &w, &h, &comp, 4);
// RIGHT: pass the actual byte length
stbi_load_from_memory(buffer, buffer_size, &w, &h, &comp, 4);
Classic C trap. Track the byte count alongside the pointer.
Check the Failure Reason
if (!data) {
fprintf(stderr, "stbi failed: %s\n", stbi_failure_reason());
}
Tells you exactly what went wrong — bad header, unsupported format, truncated data. Much faster than guessing.
Verify the Buffer
Hex-dump the first 8 bytes — a PNG starts with 89 50 4E 47. If yours doesn’t, the buffer is wrong (compressed by your archive, off by a header, etc.) and stb isn’t the problem.
Verifying
The PNG loads to the expected width/height/channels. The buffer hex matches PNG’s signature. failure_reason is never called.
“Implementation define + correct byte length + failure_reason for diagnostics. Three lines fix most stb_image bugs.”
Always check buffer_size at the call site — sizeof bugs on pointers are silent and surprisingly common in code that ‘was working’.