This is really a time-of-binding argument; the difference between a "library" and a "service" is that one is in-process and accessed over function calls, and the other is out-process and accessed over RPC.
If you change code that other services are using, you can break those other services. No way round that.
There are circumstances where they are equivalent, but they're very different overall. Namely, if you use a service, you update it once and see the new behavior everywhere. If you use a shared library, you have to update and redeploy every service. Libraries are strictly inferior in that scenario. This sounded, to me, like it was Segment's problem. They were updating shared libraries all over the place all the time.
I generally avoid creating shared libraries, they're a trap. They have a very narrow band of usefulness squeezed in between the more palatable solutions of creating new services or just copy & pasting code and allowing it to diverge for each different use-case.
While that is true, a microservices architecture can (and in my opinion should) rely on messaging and account for message schema evolution. Dependencies between services should be way less coupling than dependencies between an application and a library.
Schema evolution is just as big of a dependency hell as managing direct library dependencies. With a monolithic architecture, a lot of those concerns are contained within the context of a single repo, and can be tested much more easily than with many repos.
A library API can rely on versioning and account for schema evolution too. Even different versions can coexist if you decide that's important from the beginning (what is the same requirement as with services).
The only real difference is that services have a slow serialized network interface that fails 4 or 5 orders of magnitude more often than libraries, but can migrate over memory domains.
If you change code that other services are using, you can break those other services. No way round that.