Common scenario:
New developer: "I'm done refactoring the implementation of the BingBong class in the shared library. It was a lot of work to change and test all the frobnicateXxxx methods!"
Manager: "Wait, I thought none of our services do any frobnification?"
The old hands discuss: "They don't. Not anymore." "Are we sure? Perhaps the Foo service we haven't touched since last year?" "No, the Foo service never did." "Let's search the repos. Maybe we can delete some of these methods." "This is weird. We have seven different frobnicate methods, and we never needed to support that many different kinds of frobnification." "Of course. It's such a pain to roll out a new major version of a library, you don't want to change anything existing." "Do you remember when the rendering service was stuck on version 3 of the auth library? It was because we removed a method from the auth library and rolled out 4.0 without it. Turns out it was being used on a feature branch in the rendering service that got merged right before the release." "I remember. I'm the one who had to roll out version 4.1 the next day with exactly the same code as version 3.7."
There's a simple way of understanding how stories like this happen, and a simple conclusion: Once functionality is added to a shared library, changing it requires much more care. Therefore, shared code is much more expensive to maintain than non-shared code. This is why it makes sense to ask a question like, "Which is cheaper in the long run, maintaining three non-shared copies of this code, or maintaining one shared copy?"