Yep, you have to anyway. It's to prevent buffer overflows so that you can't "cheat" and try to stream it. You have to read it, allocate, then save it. It also means you can abort after just reading the size and ':' if it's too big. Rather than designing your protocol to allow insane buffer sizes to "stream", just have things send reasonable easily buffered chunks. That's more reliable and easier to manage.
The other reason was so it was backward compatible with netstrings. The : was already used by netstrings, but the ',' wasn't so overloading that was easiest.
It's for backwards compatibility with regular old netstrings. It works very well in practice. Implementations are dead-simple and super fast in just about every language.