Why does a String in Rust have fixed size and str variable size? The docs characterize a str as:
a pointer to some bytes, and a length
A pointer + length sounds like a fixed size to me.
A String is just a normal struct, and isn't built into the language, nor does it use any (substantive) compiler magic. Strings are just wrappers around Vec<u8>. A Vec is a pointer to a buffer, along with a size and capacity to keep track of the buffer size. Thus a String has a size of thrice usize on the heap, along with a variable amount of heap storage.
A &str is "a pointer to some bytes, and a length". It's a fat pointer with a fixed size. Notice the ampersand: an &str is different from a str. A str is a dynamically sized type that refers directly to the bytes of a string, without any reference or indirection. For the most part, you can't directly handle strs, since they don't have a fixed size, and so they must be handled behind a reference.
To summarize:
&str, which is a fat pointer to some UTF-8 bytesstr refers to some UTF-8 bytes, and usually can't be handled without some indirection