It's mathematically not possible for a hash function to guarantee an exact probability of zero collision if it shrinks space, just by virtue of the pigeon hole principle.
This means that if, for example, targeted input is on average ~20 bytes, and content can be anything within these 20 bytes, but then you want to map that "space of all possibles" into a fixed-size space of 16-byte, thanks to a 128-bit hash function, it "shrink" the space, and therefore it is mathematically necessary for many entries to share the same hash value.
That being said, it's possible to make the probability of such collision to occur so small that it does not make sense to worry about it. For example, using a 128-bit hash, the probability of collisions between millions of elements is so ridiculously small that one would have more chances to get biten by a shark and striken by a comet and win the lottery ticket all together at the exact same time. If you start to worry about that, then you have to worry about a hidden bit-flip happening inside the cpu due to a rare X-ray interaction from solar flare, which is much more probable. And of course, there are myriads of other problems, starting with software bugs, which are way way more probable than that. So focusing on the infinitesimal risk while being blind to much more common sources of issues is an incorrect stance.
Side note : not sure if it matters in your case, but note that in the case of expanding space, or even identical space, it's possible to guarantee no collision with some hash functions. For example, XXH64
and XXH3_64bits
guarantee no collision for 8-bytes->8-bytes hashes. Similarly, XXH3_128bits
guarantees no collision for 16->16 hashes. It's even easier when expanding space, for example for mapping 6-bytes input into 64-bit hashes results in no collision.
Not all hash functions guarantee this outcome though. Select the ones advertising bijective transformations.